├── .hgignore ├── LICENSE.txt ├── README.txt ├── ROADMAP.txt ├── TODO.txt ├── doc ├── protocol.rst └── readme.rst ├── misc └── download.rb ├── samples ├── setenv.sh └── virtdbg-ui.rb └── src ├── amd64 └── amd64.asm ├── dirs ├── loader ├── Makefile ├── loader.c └── sources ├── make.bat ├── metasm ├── factorize-headers.rb ├── inc │ ├── forensic1394.h │ ├── ntkrnlmp.pdb_30092be745b24fe2a311a936e7b7486f2.h │ ├── ntoskrnl.exe_F8E2A8B5C9B74BF4A6E4A48F18009994.h │ ├── virtdbg.h │ └── wdbgexts.h ├── virtdbg.rb └── virtdbg │ ├── forensic1394.rb │ ├── main.rb │ ├── system.rb │ ├── util.rb │ └── virtdbg.rb └── virtdbg ├── Makefile ├── amd64.h ├── debug.c ├── debug.h ├── driver.c ├── driver.h ├── log.c ├── log.h ├── mem.c ├── mem.h ├── misc.h ├── protocol.c ├── protocol.h ├── snprintf.c ├── snprintf.h ├── sources ├── virtdbg.c ├── virtdbg.h ├── vmx.c └── vmx.h /.hgignore: -------------------------------------------------------------------------------- 1 | syntax: glob 2 | *.pyc 3 | *.pdb 4 | 5 | syntax: regexp 6 | ^src/.*/objchk_.*$ 7 | ^src/.*/objfre_.*$ 8 | ^src/buildchk.*$ 9 | ^build/.*$ 10 | ^ext/.*$ 11 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | README 2 | ====== 3 | 4 | Virtdbg is a POC of a kernel debugger taking advantage of hardware virtualization technology. 5 | 6 | See ./doc directory. 7 | 8 | -------------------------------------------------------------------------------- /ROADMAP.txt: -------------------------------------------------------------------------------- 1 | ROADMAP 2 | ======= 3 | 4 | - loader.py script (./loader.py [vmx.sys]) 5 | - find a location for CONTROL_AREA 6 | 7 | - VMCS reconfiguration (pour catcher les exceptions) 8 | - handle processor exceptions (div by 0, etc) 9 | - cpu emulation for memory breakpoints ? 10 | - memory virtualization or buffer relocation (ptes direct manipulation) 11 | - virtualization of dr registers and debug msrs 12 | - ida debug stub ? 13 | 14 | 15 | 0.1 16 | --- 17 | 18 | - initial release 19 | 20 | 21 | 0.2 22 | --- 23 | 24 | - x86 support 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /TODO.txt: -------------------------------------------------------------------------------- 1 | TODO 2 | ==== 3 | 4 | - handle firewire write in metasm client 5 | - add support for symbols 6 | - how to load kernel symbols ? a .map extension ? 7 | - need a version packet 8 | - remove ack and reset packet 9 | - need a FORWARD event for exception 10 | - need a EVENT struct inside EXCEPTION 11 | - changing on the fly VMCS configuration 12 | - include "config.h" in hypervisor 13 | 14 | -------------------------------------------------------------------------------- /doc/protocol.rst: -------------------------------------------------------------------------------- 1 | Protocol 2 | ======== 3 | 4 | -------------------------------------------------------------------------------- /doc/readme.rst: -------------------------------------------------------------------------------- 1 | README 2 | ====== 3 | 4 | The purpose of Virtdbg is to implement a kernel debugger 5 | using the hardware virtualization technology provided by Intel (VT-x). 6 | This project is born because when it comes to Windows 7 x64, the available 7 | kernel debuggers tend to be very limited. 8 | 9 | We have WinDbg which is very good but need cooperation of the OS. We can't use 10 | it in order to debugging protected parts of the operating system like PatchGuard 11 | for example. Microsoft doesn't allow it. 12 | 13 | The other kernel debuggers are local debuggers like SoftICE, Syser or HyperDbg 14 | (which uses the same approach). I made the choice of not using a local debugger 15 | because I find that they are difficult to extend and to script. 16 | 17 | Disclaimer 18 | ---------- 19 | 20 | VirtDbg is in very alpha state. So I decline all responsabilities if your 21 | computer bluescreened ;) However I will be happy if you give it a try. 22 | It is under heavy development so expect a lot of changes quickly. 23 | 24 | Features 25 | -------- 26 | 27 | TBW 28 | 29 | Dependencies 30 | ------------ 31 | 32 | - Microsoft WDK for compiling virtdbg driver. 33 | - metasm (http://metasm.cr0.org) for the client side (gui and heavy treatments). 34 | - libforensic1394 (https://freddie.witherden.org/tools/libforensic1394/) for handling DMA communications 35 | - FireWire cable for communication between target and client. 36 | 37 | 38 | Limitations 39 | ----------- 40 | 41 | - The hypervisor is not currently signed so you need to boot in testsigning mode 42 | to load it or wait for the "dma loader". 43 | - The "dma loader" is not present in the repository for the moment because 44 | I need to port some code in ruby. For the interested persons it allows to load 45 | the virtdbg driver directly with DMA access (no need to reboot and no need for 46 | a signed driver). 47 | - Only support VT-x extension. For the persons using VT-d you need to disable it 48 | in the BIOS or the hypervisor won't load. 49 | - You will need to run Linux or MacOSX to be able to control the hypervisor 50 | because of libforensic1394. 51 | 52 | 53 | Known bugs 54 | ---------- 55 | 56 | - Sometimes a bluescreen happens when queuing DPCS. The bugcheck says 57 | "CLOCK_WATCHDOG_TIMEOUT (101)". I need to debug this... 58 | 59 | 60 | Quickstart 61 | ---------- 62 | 63 | Building 64 | ~~~~~~~~ 65 | 66 | $ cd src/virtdbg 67 | $ make 68 | 69 | 70 | Usage 71 | ~~~~~ 72 | 73 | First you must load the driver into the targeted system. To do that you can use 74 | the loader available in the src/loader directory. It is very basic but it gets 75 | the job done. 76 | 77 | $ loader.exe [path to virtdbg.sys] 78 | 79 | Then you need to connect a FireWire cable between the machines. 80 | 81 | Last you launch the client gui (which uses the metasm framework). 82 | 83 | $ cd samples/ 84 | $ ruby virtdbg-ui.rb 85 | 86 | The gui is very "softice"-like so it will be really familiar to some persons. 87 | 88 | -------------------------------------------------------------------------------- /misc/download.rb: -------------------------------------------------------------------------------- 1 | require 'net/http' 2 | 3 | server = "msdl.microsoft.com" 4 | pdb = "ntkrnlmp" 5 | guid = "30092be745b24fe2a311a936e7b7486f2" 6 | uri = "/download/symbols/#{pdb}.pdb/#{guid}/#{pdb}.pd_" 7 | dest = "#{pdb}.pd_" 8 | 9 | puts uri 10 | 11 | Net::HTTP.start(server) { |http| 12 | headers = {"User-Agent" => "Microsoft-Symbol-Server/6.6.0007.5"} 13 | resp = http.get(uri, headers) 14 | open(dest, "wb") { |file| 15 | file.write(resp.body) 16 | } 17 | } 18 | puts "Yay!!" 19 | 20 | -------------------------------------------------------------------------------- /samples/setenv.sh: -------------------------------------------------------------------------------- 1 | export RUBYLIB=../ext/metasm:../src/metasm/ 2 | export LD_LIBRARY_PATH=/usr/local/lib 3 | 4 | -------------------------------------------------------------------------------- /samples/virtdbg-ui.rb: -------------------------------------------------------------------------------- 1 | # This file is part of Virtdbg 2 | # Copyright (C) 2010-2011 Damien AUMAITRE 3 | # 4 | # Licence is GPLv3, see LICENCE.txt in the top-level directory 5 | 6 | 7 | require 'metasm' 8 | require 'virtdbg' 9 | require 'optparse' 10 | 11 | $VERBOSE = false 12 | 13 | # parse arguments 14 | opts = { :device => 0 } 15 | 16 | OptionParser.new { |opt| 17 | opt.banner = 'Usage: virtdbg.rb [options]' 18 | opt.on('--list-devices', 'list FireWire devices') { opts[:list] = true } 19 | opt.on('--device [device]', 'select FireWire device') { |h| opts[:device] = h.to_i } 20 | opt.on('-v', '--verbose') { $VERBOSE = true } # default 21 | opt.on('--debug') { $DEBUG = $VERBOSE = true } 22 | }.parse!(ARGV) 23 | 24 | def init_1394(device) 25 | bus = VirtDbg::Bus.new() 26 | bus.enable_sbp2 27 | puts "waiting for dma access..." 28 | sleep 5 29 | devices = bus.devices 30 | dev = devices[device] 31 | if not dev 32 | puts "error: requested device not found" 33 | return nil 34 | end 35 | dev.open 36 | mem = VirtDbg::FireWireMem.new(dev) 37 | puts "testing physical memory access..." 38 | puts mem.hexdump(0x8000, 0X100) 39 | mem 40 | end 41 | 42 | mem = init_1394(opts[:device]) 43 | impl = VirtDbg::VirtDbgImpl.new(mem) 44 | impl.setup 45 | dbg = VirtDbg::VirtDbg.new(impl) 46 | w = Metasm::Gui::DbgWindow.new(dbg, 'virtdbg') 47 | Metasm::Gui.main 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/amd64/amd64.asm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upring/virtdbg/38d6e354c3a295f6b5070ccd3d996eae6aa476e1/src/amd64/amd64.asm -------------------------------------------------------------------------------- /src/dirs: -------------------------------------------------------------------------------- 1 | DIRS = amd64 \ 2 | virtdbg \ 3 | loader 4 | 5 | -------------------------------------------------------------------------------- /src/loader/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source 3 | # file to this component. This file merely indirects to the real make file 4 | # that is shared by all the components of NT OS/2 5 | # 6 | ! INCLUDE $(NTMAKEENV)\makefile.def 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/loader/loader.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | void PrintError() 8 | { 9 | DWORD dw; 10 | LPVOID lpMsg; 11 | dw = GetLastError(); 12 | 13 | FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 14 | NULL, 15 | dw, 16 | MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), 17 | (char *) &lpMsg, 18 | 0, 19 | NULL); 20 | 21 | printf("error 0x%08x:%s\n", dw, (char*)lpMsg); 22 | } 23 | 24 | 25 | int _cdecl main(int argc, char **argv) 26 | { 27 | HANDLE hSCManager; 28 | HANDLE hService; 29 | SERVICE_STATUS ss; 30 | BOOL bStatus; 31 | char buffer[4096]; 32 | 33 | if (argc != 2) 34 | { 35 | printf("Usage: %s \n", argv[0]); 36 | return 0; 37 | } 38 | 39 | bStatus = GetFullPathNameA(argv[1], 4096, buffer, NULL); 40 | 41 | if (bStatus == 0) 42 | { 43 | PrintError(); 44 | return -1; 45 | } 46 | 47 | hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE); 48 | 49 | if (hSCManager == NULL) 50 | { 51 | printf("Can't open SCManager\n"); 52 | PrintError(); 53 | return -1; 54 | } 55 | 56 | printf("Loading driver ...\n"); 57 | 58 | printf("Creating service ...\n"); 59 | 60 | hService = CreateServiceA(hSCManager, "Virtdbg", 61 | "VirtDbg driver", 62 | SERVICE_START | DELETE | SERVICE_STOP, 63 | SERVICE_KERNEL_DRIVER, 64 | SERVICE_DEMAND_START, 65 | SERVICE_ERROR_NORMAL, 66 | buffer, 67 | NULL, NULL, NULL, NULL, NULL); 68 | 69 | if (hService == NULL) 70 | { 71 | printf("Can't create service, maybe service already created\n"); 72 | PrintError(); 73 | printf("Opening service...\n"); 74 | 75 | hService = OpenServiceA(hSCManager, "Virtdbg", 76 | SERVICE_START | DELETE | SERVICE_STOP); 77 | if (hService == NULL) 78 | { 79 | printf("Can't open service\n"); 80 | PrintError(); 81 | goto err; 82 | } 83 | } 84 | 85 | printf("Starting service\n"); 86 | 87 | bStatus = StartService(hService, 0, NULL); 88 | 89 | if (bStatus == 0) 90 | { 91 | printf("Can't start service\n"); 92 | PrintError(); 93 | goto err; 94 | } 95 | 96 | printf("Press a key to close service\n"); 97 | getchar(); 98 | 99 | bStatus = ControlService(hService, SERVICE_CONTROL_STOP, &ss); 100 | 101 | if (bStatus == 0) 102 | { 103 | printf("Can't stop service\n"); 104 | PrintError(); 105 | goto err; 106 | } 107 | 108 | err: 109 | DeleteService(hService); 110 | CloseServiceHandle(hService); 111 | CloseServiceHandle(hSCManager); 112 | 113 | return 0; 114 | } 115 | -------------------------------------------------------------------------------- /src/loader/sources: -------------------------------------------------------------------------------- 1 | TARGETNAME=loader 2 | TARGETPATH=..\..\build\loader 3 | TARGETTYPE=PROGRAM 4 | UMTYPE=console 5 | USE_LIBCMT=1 6 | 7 | SOURCES=loader.c 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/make.bat: -------------------------------------------------------------------------------- 1 | build -czgw 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/metasm/factorize-headers.rb: -------------------------------------------------------------------------------- 1 | # This file is part of Metasm, the Ruby assembly manipulation suite 2 | # Copyright (C) 2006-2009 Yoann GUILLOT 3 | # 4 | # Licence is LGPL, see LICENCE in the top-level directory 5 | 6 | # 7 | # this exemple illustrates the use of the cparser/preprocessor #factorize functionnality: 8 | # we write some code using standard headers, and the factorize call on CParser 9 | # gives us back the macro/C definitions that we use in our code, so that we can 10 | # get rid of the header 11 | # Argument: C file to factorize, [path to visual studio installation] 12 | # with a single argument, uses GCC standard headers 13 | # 14 | 15 | require 'metasm' 16 | include Metasm 17 | 18 | abort 'target needed' if not file = ARGV.shift 19 | 20 | visualstudiopath = ARGV.shift 21 | if visualstudiopath 22 | stub = < 4 | 5 | libforensic1394 is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, either version 3 of the 8 | License, or (at your option) any later version. 9 | 10 | libforensic1394 is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with libforensic1394. If not, see 17 | . 18 | */ 19 | 20 | /** 21 | * \file forensic1394.h 22 | * 23 | * \brief Main header file for libforensic1394. 24 | */ 25 | 26 | /** 27 | * \mainpage libforensic1394 28 | * 29 | * The latest version of libforensic1394 can be found at: 30 | * https://freddie.witherden.org/tools/libforensic1394/ 31 | * 32 | * This API gives you access to the FireWire bus of contemporary operating 33 | * systems in order to facilitate digital forensics on an attached device. 34 | * Unlike existing APIs Forensic1394 is: 35 | * - Modern; unlike existing FireWire libraries Forensic1394 supports the 36 | * new `Juju' stack introduced in Linux 2.6.22. 37 | * - Portable; with platform drivers existing for both Linux (Juju stack 38 | * only) and Mac OS X (via I/O Kit). 39 | * - Minimal; only functions required for performing digital forensics are 40 | * provided. 41 | * 42 | * By omitting features not required in forensic applications (such as 43 | * isochronous transfers) the API is both simple to use and port. For example 44 | * the memory of an attached device can be read using the following code: 45 | * 46 | * \code 47 | * forensic1394_bus *bus; 48 | * forensic1394_dev **dev; 49 | * char data[512]; 50 | * 51 | * // Allocate a bus handle 52 | * bus = forensic1394_alloc(); 53 | * assert(bus); 54 | * 55 | * // Enabls SBP-2; required for memory access to some systems 56 | * forensic1394_enable_sbp2(bus); 57 | * 58 | * // Give the bus time to reinitialise 59 | * sleep(2); 60 | * 61 | * // Get the devices attached to the systen 62 | * dev = forensic1394_get_devices(bus, NULL, NULL); 63 | * assert(dev); 64 | * 65 | * // Open the first device 66 | * forensic1394_open_device(dev[0]); 67 | * 68 | * // Read some memory from the device 69 | * forensic1394_read_device(dev[0], 50 * 1024 * 1024, 512, data); 70 | * 71 | * // Data now contains 512 bytes of memory starting at an offset of 50MiB 72 | * 73 | * // Close the device and destroy the bus 74 | * forensic1394_close_device(dev[0]); 75 | * forensic1394_destroy(bus); 76 | * \endcode 77 | * 78 | * \section sbp2 Enabling SBP-2 79 | * In order to gain direct memory access to certain systems, namely Windows and 80 | * GNU/Linux, it is necessary to present the target system with an SBP-2 unit 81 | * directory. This can be done by calling ::forensic1394_enable_sbp2. It is 82 | * usual for devices on the bus to take a couple of seconds to react to this 83 | * change. Therefore, client applications should ideally wait for ~2 seconds 84 | * before attempting to read or write to a device. Although there are 85 | * provisions in the SBP-2 specification to determine when a target system has 86 | * enabled the DMA filter, client-side API limitations currently prevent 87 | * libforensic1394 from leveraging this. 88 | * 89 | * \section reset Handling Bus Resets 90 | * Bus resets occur when devices are added/removed from the system or when the 91 | * configuration ROM of a device is updated. The following methods are 92 | * affected by bus resets: 93 | * - ::forensic1394_open_device 94 | * - ::forensic1394_read_device 95 | * - ::forensic1394_read_device_v 96 | * - ::forensic1394_write_device 97 | * - ::forensic1394_write_device_v 98 | * 99 | * After a bus reset calls to all of these methods will result in 100 | * #FORENSIC1394_RESULT_BUS_RESET being returned. Applications should 101 | * handle this by saving the GUIDs of any devices being accessed and then call 102 | * ::forensic1394_get_devices. Calling this will void all device handles. 103 | * The new list of devices can then be iterated through and their GUIDs 104 | * compared against saved GUIDs. The GUID of a device can be obtained by 105 | * calling ::forensic1394_get_device_guid. 106 | * 107 | * \section thread Thread Safety 108 | * libforensic1394 is thread safe at the device level with the restriction 109 | * that devices can only be accessed by the thread that opened them. This is 110 | * because some backends, namely Mac OS X/IOKit, install thread-specific 111 | * callback dispatchers upon opening a device. When using multiple threads of 112 | * execution care must be taken when calling ::forensic1394_get_devices (which 113 | * closes and destroys any open device handles). It is the responsibility of 114 | * the caller to ensure that this is safe. The process can be simplified 115 | * through the use of an \a ondestroy callback handler. 116 | * 117 | * \author Freddie Witherden 118 | */ 119 | 120 | #ifndef _FORENSIC_1394_H 121 | #define _FORENSIC_1394_H 122 | 123 | #ifdef __cplusplus 124 | extern "C" 125 | { 126 | #endif 127 | 128 | #if defined(FORENSIC1394_DECL) 129 | // No op 130 | #elif defined(_MSC_VER) 131 | # define FORENSIC1394_DECL __declspec(dllexport) 132 | #elif (__GNUC__ >= 3) 133 | # define FORENSIC1394_DECL __attribute__((visibility("default"))) 134 | #else 135 | # define FORENSIC1394_DECL 136 | #endif 137 | 138 | typedef long int64_t; 139 | typedef unsigned long size_t; 140 | typedef unsigned short uint16_t; 141 | typedef unsigned int uint32_t; 142 | typedef unsigned long uint64_t; 143 | 144 | 145 | /// An opaque bus handle 146 | typedef struct _forensic1394_bus forensic1394_bus; 147 | 148 | /// An opaque device handle 149 | typedef struct _forensic1394_dev forensic1394_dev; 150 | 151 | /** 152 | * \brief A request structure used for making batch read/write requests. 153 | * 154 | * For use with the batch APIs (suffixed by _v) requests allow 155 | * forensic1394 to take advantage of the asynchronous capabilities of 156 | * FireWire stacks in order to improve performance. 157 | * 158 | * \sa forensic1394_read_device_v 159 | * \sa forensic1394_write_device_v 160 | */ 161 | typedef struct _forensic1394_req 162 | { 163 | /// The address to read/write 164 | uint64_t addr; 165 | 166 | /// Length of the buffer in bytes 167 | size_t len; 168 | 169 | /// Data buffer 170 | void *buf; 171 | } forensic1394_req; 172 | 173 | /** 174 | * \brief Number of uint32 elements required to store a device ROM. 175 | * 176 | * A FireWire configuration status ROM (CSR) is made up of unsigned 32-bit 177 | * integers. The maximum size of a ROM is 1024 bytes, giving 256 elements. 178 | */ 179 | #define FORENSIC1394_CSR_SZ 256 180 | 181 | /** 182 | * A function to be called when a ::forensic1394_dev is about to be destroyed. 183 | * This should be passed to ::forensic1394_get_devices and will be associated 184 | * with all devices returned by the method. The callback will fire either when 185 | * the bus is destroyed via ::forensic1394_destroy or the next time that 186 | * ::forensic1394_get_devices is called (which has the implicit effect of 187 | * destroying all existing devices first). 188 | * 189 | * If user data is required it can be attached on either a per-bus or per-device 190 | * level. 191 | * 192 | * \param bus The bus owning the device. 193 | * \param dev The device being destroyed. 194 | * 195 | * \sa forensic1394_set_bus_user_data 196 | * \sa forensic1394_set_device_user_data 197 | */ 198 | typedef void (*forensic1394_device_callback) (forensic1394_bus *bus, 199 | forensic1394_dev *dev); 200 | 201 | /** 202 | * \brief Possible return status codes. 203 | * 204 | * In general methods return 0 on success and a negative integer on failure. 205 | * These codes may be used to ascertain precisely why a method failed. It is 206 | * worth noting that invalid input parameters are handled with assertions as 207 | * opposed to status codes. 208 | * 209 | * \sa forensic1394_get_result_str 210 | */ 211 | typedef enum 212 | { 213 | /// No errors encountered 214 | FORENSIC1394_RESULT_SUCCESS = 0, 215 | /// General, unspecified, error 216 | FORENSIC1394_RESULT_OTHER_ERROR = -1, 217 | /// A bus reset has occured 218 | FORENSIC1394_RESULT_BUS_RESET = -2, 219 | /// Permissions related error 220 | FORENSIC1394_RESULT_NO_PERM = -3, 221 | /// Device is busy 222 | FORENSIC1394_RESULT_BUSY = -4, 223 | /// General I/O error 224 | FORENSIC1394_RESULT_IO_ERROR = -5, 225 | /// Bad transfer size (normally too large) 226 | FORENSIC1394_RESULT_IO_SIZE = -6, 227 | /// I/O Timeout 228 | FORENSIC1394_RESULT_IO_TIMEOUT = -7, 229 | /// Sentinel; internal use only 230 | FORENSIC1394_RESULT_END = -8 231 | } forensic1394_result; 232 | 233 | /** 234 | * \brief Allocates a new forensic1394 handle. 235 | * 236 | * This handle can then be used to query the devices attached to the bus and to 237 | * update the configuration status ROM (CSR) of the bus. 238 | * 239 | * \return A handle to a forensic1394_bus on success, NULL otherwise. 240 | */ 241 | FORENSIC1394_DECL forensic1394_bus *forensic1394_alloc(void); 242 | 243 | /** 244 | * \brief Provides an SBP-2 unit directory; required for DMA to Windows systems. 245 | * 246 | * Updates the configuration status ROM of the bus to contain an SBP-2 247 | * unit directory. This is required in order for some connected 248 | * devices to allow for direct memory access (`DMA'). 249 | * 250 | * Note that this is usually a global change, affecting all FireWire 251 | * ports on the system. 252 | * 253 | * As calling this method usually results in a bus reset it is advisable to 254 | * call it as soon as a bus is available. 255 | * 256 | * \param bus The 1394 bus to add the SBP-2 unit directory to. 257 | * \return A result status code. 258 | */ 259 | FORENSIC1394_DECL forensic1394_result 260 | forensic1394_enable_sbp2(forensic1394_bus *bus); 261 | 262 | /** 263 | * \brief Gets the devices attached to the FireWire bus. 264 | * 265 | * This method scans the (foreign) devices attached to \a bus and returns a 266 | * NULL-terminated list of them. 267 | * 268 | * The out-parameter \a ndev, if not NULL, serves a dual purpose. After a call 269 | * to the function if \a *ndev is: 270 | * 271 | * - >= 0 then the call was successful and it contains the number of devices 272 | * attached to the system, which may be 0 if no devices are attached. 273 | * - < 0 then the call was not successful and it contains the appropriate 274 | * ::forensic1394_result error code. 275 | * 276 | * Getting the attached devices is a destructive process; voiding any existing 277 | * device handles. To compensate for this the \a ondestroy callback is 278 | * provided. This argument, if not NULL, will be called when the new device 279 | * list is destroyed, usually as a result of a subsequent call to 280 | * ::forensic1394_get_devices or a call to ::forensic1394_destroy. The 281 | * function is called for each device in the list. 282 | * 283 | * \warning Calling this method will invalidate all active device handles. 284 | * 285 | * \param bus The bus to get the devices for. 286 | * \param[out] ndev The number of devices found; NULL is acceptable. 287 | * \param[in] ondestroy Function to be called when the returned device list is 288 | * destroyed; NULL for no callback. 289 | * \return A NULL-terminated list of devices. 290 | * 291 | * \sa forensic1394_device_callback 292 | * \sa forensic1394_result 293 | */ 294 | FORENSIC1394_DECL forensic1394_dev ** 295 | forensic1394_get_devices(forensic1394_bus *bus, 296 | int *ndev, 297 | forensic1394_device_callback ondestroy); 298 | 299 | /** 300 | * \brief Destroys a bus handle. 301 | * 302 | * Releases all of the memory associated with the handle, closing any open 303 | * devices. After a call to this method all forensic1394 device handles are 304 | * invalidated. 305 | * 306 | * \param bus The forensic1394_bus to destroy. 307 | */ 308 | FORENSIC1394_DECL void 309 | forensic1394_destroy(forensic1394_bus *bus); 310 | 311 | /** 312 | * \brief Fetches the user data for \a bus. 313 | * 314 | * Returns the user data for \a bus. If ::forensic1394_set_bus_user_data is 315 | * yet to be called on the bus the result is undefined. 316 | * 317 | * \param bus The bus. 318 | * \return The user data associated with the bus. 319 | * 320 | * \sa forensic1394_set_bus_user_data 321 | */ 322 | FORENSIC1394_DECL void * 323 | forensic1394_get_bus_user_data(forensic1394_bus *bus); 324 | 325 | /** 326 | * \brief Sets the user data for the bus. 327 | * 328 | * \param bus The bus. 329 | * \param[in] u The user data to set. 330 | * 331 | * \sa forensic1394_get_bus_user_data 332 | */ 333 | FORENSIC1394_DECL void 334 | forensic1394_set_bus_user_data(forensic1394_bus *bus, void *u); 335 | 336 | /** 337 | * \brief Opens the device \a dev for reading/writing. 338 | * 339 | * It is necessary to open a device before attempting to read/write from it. 340 | * 341 | * \param dev The device to open. 342 | * \return A result status code. 343 | * 344 | * \sa forensic1394_close_device 345 | */ 346 | FORENSIC1394_DECL forensic1394_result 347 | forensic1394_open_device(forensic1394_dev *dev); 348 | 349 | /** 350 | * \brief Closes the device \a dev. 351 | * 352 | * This can only be called on an open device. 353 | * 354 | * \param dev The device to close. 355 | */ 356 | FORENSIC1394_DECL void 357 | forensic1394_close_device(forensic1394_dev *dev); 358 | 359 | /** 360 | * \brief Checks if a device is open or not. 361 | * 362 | * \param dev The FireWire device. 363 | * \return Non-zero if the device is open; 0 if it is closed. 364 | */ 365 | FORENSIC1394_DECL int 366 | forensic1394_is_device_open(forensic1394_dev *dev); 367 | 368 | /** 369 | * \brief Reads \a len bytes from \a dev starting at \a addr into \a buf. 370 | * 371 | * Performs a blocking (synchronous) read on the device \a dev, starting at the 372 | * address \a addr and attempting to read \a len bytes. The resulting bytes 373 | * are copied into \a buf. 374 | * 375 | * It is worth noting that many devices impose a limit on the maximum transfer 376 | * size. This limit can be obtained by calling 377 | * ::forensic1394_get_device_request_size and is usually 2048 bytes in size. 378 | * 379 | * This method is a convenience wrapper around ::forensic1394_read_device_v. 380 | * 381 | * \param dev The device to read from. 382 | * \param addr The memory address to start reading from. 383 | * \param len The number of bytes to read. 384 | * \param[out] buf The buffer to copy the read bytes into; must be at least 385 | * \a len bytes in size. 386 | * \return A result status code. 387 | * 388 | * \sa forensic1394_get_device_request_size 389 | * \sa forensic1394_read_device_v 390 | */ 391 | FORENSIC1394_DECL forensic1394_result 392 | forensic1394_read_device(forensic1394_dev *dev, 393 | uint64_t addr, 394 | size_t len, 395 | void *buf); 396 | 397 | /** 398 | * \brief Reads each request specified in \a req from \a dev asynchronously. 399 | * 400 | * Vectorised, scatter input, read method. By issuing requests asynchronously 401 | * this function is often able to offer better performance than a series of 402 | * ::forensic1394_read_device calls. The performance gains, if any, depend 403 | * heavily on the capabilities of the backend. 404 | * 405 | * Each request must be no larger than ::forensic1394_get_device_request_size 406 | * bytes. If any of the data buffers in \a req overlap then the behaviour 407 | * is undefined. 408 | * 409 | * The method will return early should one of the requests fail. It is not 410 | * currently possible to determine which request caused the error. 411 | * 412 | * \param dev The device to read from. 413 | * \param req The read requests to service. 414 | * \param nreq The number of requests in \a req. 415 | * \return A result status code. 416 | */ 417 | FORENSIC1394_DECL forensic1394_result 418 | forensic1394_read_device_v(forensic1394_dev *dev, 419 | forensic1394_req *req, 420 | size_t nreq); 421 | 422 | /** 423 | * \brief Writes \a len bytes from \a buf to \a dev starting at \a addr. 424 | * 425 | * Performs a blocking (synchronous) write on the device \a dev attempting to 426 | * copy \a len bytes from \a buf to the device address \a addr. See 427 | * the documentation for ::forensic1394_read_device for a discussion on the 428 | * maximum transfer size. 429 | * 430 | * This method is a convenience wrapper around ::forensic1394_write_device_v. 431 | * 432 | * \param dev The device to write to. 433 | * \param addr The memory address to start writing to. 434 | * \param len The number of bytes to write. 435 | * \param[in] buf The buffer to write. 436 | * \return A result status code. 437 | * 438 | * \a forensic1394_read_device 439 | */ 440 | FORENSIC1394_DECL forensic1394_result 441 | forensic1394_write_device(forensic1394_dev *dev, 442 | uint64_t addr, 443 | size_t len, 444 | void *buf); 445 | 446 | /** 447 | * \brief Writes each request specified in \a req to \a dev asynchronously. 448 | * 449 | * The vectorised, gather output, write method. Depending on the backend this 450 | * method may issue the requests in \a req asynchronously in order to improve 451 | * performance. See ::forensic1394_read_device_v for further discussion. 452 | * 453 | * \param dev The device to write to. 454 | * \param[in] req The write requests to service. 455 | * \param nreq The number of requests in \a req. 456 | * \return A result status code. 457 | */ 458 | FORENSIC1394_DECL forensic1394_result 459 | forensic1394_write_device_v(forensic1394_dev *dev, 460 | const forensic1394_req *req, 461 | size_t nreq); 462 | 463 | /** 464 | * \brief Copies the configuration ROM for the device \a dev into \a rom. 465 | * 466 | * Fetches the configuration status ROM (CSR) for the device and copies it 467 | * into \a rom. This is assumed to be of at least #FORENSIC1394_CSR_SZ 468 | * elements in size. Any unused space will be filled with zeros. 469 | * 470 | * \param dev The device. 471 | * \param rom The array to copy the CSR into. 472 | */ 473 | FORENSIC1394_DECL void 474 | forensic1394_get_device_csr(forensic1394_dev *dev, 475 | uint32_t *rom); 476 | 477 | /** 478 | * \brief Returns the node ID of the device. 479 | * 480 | * It is important to note that this value does not remain constant across bus 481 | * resets and is hence unsuitable for device identification. 482 | * 483 | * \param dev The device. 484 | * \return The node ID of the device. 485 | */ 486 | FORENSIC1394_DECL uint16_t 487 | forensic1394_get_device_nodeid(forensic1394_dev *dev); 488 | 489 | /** 490 | * \brief Returns the GUID of the device. 491 | * 492 | * This is a 48-bit value, similar to a MAC address, that uniquely identifies 493 | * a FireWire device. 494 | * 495 | * \param dev The device. 496 | * \return The GUID of the device. 497 | */ 498 | FORENSIC1394_DECL int64_t 499 | forensic1394_get_device_guid(forensic1394_dev *dev); 500 | 501 | /** 502 | * \brief Returns the product name of the device, if any. 503 | * 504 | * Should the property not exist for the device an empty string ("") is 505 | * returned. The string is guaranteed to remain valid for the lifetime of the 506 | * device. 507 | * 508 | * \param dev The device. 509 | * \return The product name of the device, if any. 510 | */ 511 | FORENSIC1394_DECL const char * 512 | forensic1394_get_device_product_name(forensic1394_dev *dev); 513 | 514 | /** 515 | * \brief Returns the product ID of the device, if any. 516 | * 517 | * Should the property not exist then 0 is returned. 518 | * 519 | * \param dev The device. 520 | * \return The product ID of the device, or 0 if it is not defined. 521 | */ 522 | FORENSIC1394_DECL int 523 | forensic1394_get_device_product_id(forensic1394_dev *dev); 524 | 525 | /** 526 | * \brief Returns the vendor name of the device, if any. 527 | * 528 | * Should the property not exist for the device an empty string ("") is 529 | * returned. The string is guaranteed to remain valid for the lifetime of the 530 | * device. 531 | * 532 | * \param dev The device. 533 | * \return The vendor name of the device, if any. 534 | */ 535 | FORENSIC1394_DECL const char * 536 | forensic1394_get_device_vendor_name(forensic1394_dev *dev); 537 | 538 | /** 539 | * \brief Returns the vendor ID of the device, if any. 540 | * 541 | * Should the property not exist then 0 is returned. 542 | * 543 | * \param dev The device. 544 | * \return The vendor ID of the device, or 0 if it is not defined. 545 | */ 546 | FORENSIC1394_DECL int 547 | forensic1394_get_device_vendor_id(forensic1394_dev *dev); 548 | 549 | /** 550 | * \brief Returns the maximum request size supported by the device. 551 | * 552 | * Parses the configuration status ROM for the device and extracts the maximum 553 | * supported request size (usually 2048 bytes). This value should be taken as 554 | * an upper-bound for the length of read/write calls. If a size can not be 555 | * found in the CSR then 512 bytes will be returned. 556 | * 557 | * The returned size is guaranteed to be a positive power of two. 558 | * 559 | * \param dev The device. 560 | * \return The maximum request size in bytes. 561 | */ 562 | FORENSIC1394_DECL int 563 | forensic1394_get_device_request_size(forensic1394_dev *dev); 564 | 565 | /** 566 | * \brief Fetches the user data for the device \a dev. 567 | * 568 | * If ::forensic1394_set_device_user_data is yet to be called on the device the 569 | * result is undefined. 570 | * 571 | * \param dev The device. 572 | * \return The user data associated with the device. 573 | * 574 | * \sa forensic1394_set_device_user_data 575 | */ 576 | FORENSIC1394_DECL void * 577 | forensic1394_get_device_user_data(forensic1394_dev *dev); 578 | 579 | /** 580 | * \brief Sets the user data for the device \a dev to \a u. 581 | * 582 | * \param dev The device. 583 | * \param[in] u The user data to set. 584 | * 585 | * \sa forensic1394_get_device_user_data 586 | */ 587 | FORENSIC1394_DECL void 588 | forensic1394_set_device_user_data(forensic1394_dev *dev, void *u); 589 | 590 | /** 591 | * \brief Converts a return status code to a string. 592 | * 593 | * Returns a textual representation of the return status code \a result. The 594 | * string returned is guaranteed to be valid for the lifetime of the program. 595 | * 596 | * In the event of an invalid code NULL is returned. 597 | * 598 | * \param r The return status code. 599 | * \return A description of the error code on success; NULL otherwise. 600 | */ 601 | FORENSIC1394_DECL const char * 602 | forensic1394_get_result_str(forensic1394_result r); 603 | 604 | #ifdef __cplusplus 605 | } 606 | #endif 607 | 608 | #endif // _FORENSIC_1394_H 609 | 610 | 611 | 612 | -------------------------------------------------------------------------------- /src/metasm/inc/virtdbg.h: -------------------------------------------------------------------------------- 1 | 2 | typedef unsigned long ULONG; 3 | typedef ULONG *PULONG; 4 | typedef unsigned short USHORT; 5 | typedef USHORT *PUSHORT; 6 | typedef unsigned char UCHAR; 7 | typedef UCHAR *PUCHAR; 8 | typedef char *PSZ; 9 | 10 | typedef char CHAR; 11 | typedef short SHORT; 12 | typedef long LONG; 13 | typedef int INT; 14 | typedef SHORT *PSHORT; // winnt 15 | typedef LONG *PLONG; // winnt 16 | 17 | typedef __int64 LONGLONG; 18 | typedef unsigned __int64 ULONGLONG; 19 | typedef void *PVOID; 20 | 21 | typedef signed char INT8, *PINT8; 22 | typedef signed short INT16, *PINT16; 23 | typedef signed int INT32, *PINT32; 24 | typedef signed __int64 INT64, *PINT64; 25 | typedef unsigned char UINT8, *PUINT8; 26 | typedef unsigned short UINT16, *PUINT16; 27 | typedef unsigned int UINT32, *PUINT32; 28 | typedef unsigned __int64 UINT64, *PUINT64; 29 | 30 | typedef signed int LONG32, *PLONG32; 31 | typedef unsigned int ULONG32, *PULONG32; 32 | 33 | typedef __int64 LONG64, *PLONG64; 34 | typedef unsigned __int64 ULONG64, *PULONG64; 35 | typedef unsigned __int64 DWORD64, *PDWORD64; 36 | 37 | typedef struct _LARGE_INTEGER_unnamed1 { 38 | ULONG32 LowPart; 39 | LONG32 HighPart; 40 | } LARGE_INTEGER_unnamed1; 41 | 42 | typedef union _LARGE_INTEGER { 43 | LARGE_INTEGER_unnamed1 u; 44 | LONG64 QuadPart; 45 | } LARGE_INTEGER; 46 | 47 | typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS; 48 | 49 | typedef struct _VIRTDBG_CONTROL_AREA 50 | { 51 | ULONG32 Magic1; 52 | ULONG32 Magic2; 53 | PHYSICAL_ADDRESS SendArea; 54 | PHYSICAL_ADDRESS RecvArea; 55 | PVOID KernelBase; 56 | PVOID DebuggerData; 57 | PHYSICAL_ADDRESS LogBuffer; 58 | ULONG32 ClientId; 59 | ULONG32 ServerId; 60 | ULONG32 LastClientId; 61 | ULONG32 LastServerId; 62 | LONG State; 63 | } VIRTDBG_CONTROL_AREA, *PVIRTDBG_CONTROL_AREA; 64 | 65 | #define CONTROL_AREA_SIZE 0x1000 66 | #define CONTROL_AREA_MAGIC1 0xbabebabe 67 | #define CONTROL_AREA_MAGIC2 0xcafecafe 68 | 69 | typedef struct _PACKET_HEADER { 70 | ULONG32 Magic; 71 | ULONG32 Type; 72 | ULONG32 Size; 73 | ULONG32 Id; 74 | ULONG32 ClientId; 75 | ULONG32 Checksum; 76 | } PACKET_HEADER, *PPACKET_HEADER; 77 | 78 | typedef struct _BREAKIN_PACKET { 79 | ULONG64 Cr3; 80 | } BREAKIN_PACKET, *PBREAKIN_PACKET; 81 | 82 | #define CONTINUE_STATUS_SINGLE_STEP 0x1 83 | #define CONTINUE_STATUS_UNLOAD 0x2 84 | #define CONTINUE_STATUS_CONTINUE 0x3 85 | 86 | typedef struct _CONTINUE_PACKET { 87 | ULONG32 Status; 88 | } CONTINUE_PACKET, *PCONTINUE_PACKET; 89 | 90 | typedef struct _SOFTWARE_BREAKPOINT_PACKET { 91 | ULONG64 Address; 92 | } SOFTWARE_BREAKPOINT_PACKET, *PSOFTWARE_BREAKPOINT_PACKET; 93 | 94 | typedef struct _HARDWARE_BREAKPOINT_PACKET { 95 | ULONG64 Address; 96 | } HARDWARE_BREAKPOINT_PACKET, *PHARDWARE_BREAKPOINT_PACKET; 97 | 98 | typedef struct _MEMORY_BREAKPOINT_PACKET { 99 | ULONG64 Address; 100 | } MEMORY_BREAKPOINT_PACKET, *PMEMORY_BREAKPOINT_PACKET; 101 | 102 | typedef struct _STATE_CHANGE_PACKET { 103 | ULONG32 Exception; 104 | ULONG64 Address; 105 | } STATE_CHANGE_PACKET, *PSTATE_CHANGE_PACKET; 106 | 107 | typedef struct _READ_VIRTUAL_MEMORY_PACKET { 108 | ULONG64 Address; 109 | ULONG32 Size; 110 | } READ_VIRTUAL_MEMORY_PACKET, *PREAD_VIRTUAL_MEMORY_PACKET; 111 | 112 | typedef struct _WRITE_VIRTUAL_MEMORY_PACKET { 113 | ULONG64 Address; 114 | ULONG32 Size; 115 | } WRITE_VIRTUAL_MEMORY_PACKET, *PWRITE_VIRTUAL_MEMORY_PACKET; 116 | 117 | typedef struct _READ_PHYSICAL_MEMORY_PACKET { 118 | ULONG64 Address; 119 | ULONG32 Size; 120 | } READ_PHYSICAL_MEMORY_PACKET, *PREAD_PHYSICAL_MEMORY_PACKET; 121 | 122 | typedef struct _WRITE_PHYSICAL_MEMORY_PACKET { 123 | ULONG64 Address; 124 | ULONG32 Size; 125 | } WRITE_PHYSICAL_MEMORY_PACKET, *PWRITE_PHYSICAL_MEMORY_PACKET; 126 | 127 | typedef struct _DEBUG_CONTEXT { 128 | ULONG64 rax; 129 | ULONG64 rbx; 130 | ULONG64 rcx; 131 | ULONG64 rdx; 132 | ULONG64 rsi; 133 | ULONG64 rdi; 134 | ULONG64 rbp; 135 | ULONG64 rsp; 136 | ULONG64 r8; 137 | ULONG64 r9; 138 | ULONG64 r10; 139 | ULONG64 r11; 140 | ULONG64 r12; 141 | ULONG64 r13; 142 | ULONG64 r14; 143 | ULONG64 r15; 144 | ULONG64 rip; 145 | ULONG64 rflags; 146 | ULONG64 cr0; 147 | ULONG64 cr3; 148 | ULONG64 cr4; 149 | ULONG64 cr8; 150 | ULONG64 dr0; 151 | ULONG64 dr1; 152 | ULONG64 dr2; 153 | ULONG64 dr3; 154 | ULONG64 dr6; 155 | ULONG64 dr7; 156 | USHORT cs; 157 | USHORT ds; 158 | USHORT es; 159 | USHORT fs; 160 | USHORT ss; 161 | USHORT gs; 162 | } DEBUG_CONTEXT, *PDEBUG_CONTEXT; 163 | 164 | typedef struct _GET_CONTEXT_PACKET { 165 | ULONG32 Flags; 166 | } GET_CONTEXT_PACKET, *PGET_CONTEXT_PACKET; 167 | 168 | typedef struct _SET_CONTEXT_PACKET { 169 | ULONG32 Flags; 170 | } SET_CONTEXT_PACKET, *PSET_CONTEXT_PACKET; 171 | 172 | typedef struct _MANIPULATE_STATE_PACKET { 173 | ULONG32 ApiNumber; 174 | ULONG32 Error; 175 | union { 176 | READ_VIRTUAL_MEMORY_PACKET ReadVirtualMemory; 177 | WRITE_VIRTUAL_MEMORY_PACKET WriteVirtualMemory; 178 | READ_PHYSICAL_MEMORY_PACKET ReadPhysicalMemory; 179 | WRITE_PHYSICAL_MEMORY_PACKET WritePhysicalMemory; 180 | GET_CONTEXT_PACKET GetContext; 181 | SET_CONTEXT_PACKET SetContext; 182 | } u; 183 | } MANIPULATE_STATE_PACKET, *PMANIPULATE_STATE_PACKET; 184 | 185 | #define PACKET_TYPE_RESET 1 186 | #define PACKET_TYPE_BREAKIN 2 187 | #define PACKET_TYPE_ACK 3 188 | #define PACKET_TYPE_RESEND 4 189 | #define PACKET_TYPE_STATE_CHANGE 5 190 | #define PACKET_TYPE_MANIPULATE_STATE 6 191 | #define PACKET_TYPE_CONTINUE 7 192 | 193 | #define READ_VIRTUAL_MEMORY_API 0x41 194 | #define WRITE_VIRTUAL_MEMORY_API 0x42 195 | #define GET_CONTEXT_API 0x43 196 | #define SET_CONTEXT_API 0x44 197 | 198 | #define INITIAL_ID 0x41424344 199 | #define PACKET_MAGIC 0xdeadbabe 200 | 201 | #define MAX_PACKET_SIZE 0x800 202 | 203 | #define MAX_RETRIES 0x1000000 204 | #define HEADER_SIZE sizeof(PACKET_HEADER) 205 | 206 | 207 | -------------------------------------------------------------------------------- /src/metasm/inc/wdbgexts.h: -------------------------------------------------------------------------------- 1 | /*++ 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | Module Name: 6 | 7 | wdbgexts.h 8 | 9 | Abstract: 10 | 11 | This file contains the necessary prototypes and data types for a user 12 | to write a debugger extension DLL. This header file is also included 13 | by the NT debuggers (WINDBG & KD). 14 | 15 | This header file must be included after "windows.h" and "dbghelp.h". 16 | 17 | Please see the NT DDK documentation for specific information about 18 | how to write your own debugger extension DLL. 19 | 20 | Environment: 21 | 22 | Win32 only. 23 | 24 | Revision History: 25 | 26 | --*/ 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | 32 | #define VOID void 33 | #define STDCALL __stdcall 34 | #define FASTCALL __fastcall 35 | #define CDECL __cdecl 36 | #define THISCALL __thiscall 37 | #define NEAR 38 | #define FAR 39 | 40 | typedef signed char INT8; 41 | typedef signed char CHAR; 42 | typedef unsigned char UCHAR; 43 | typedef signed short INT16; 44 | typedef signed int INT32; 45 | typedef signed int BOOL; 46 | typedef signed __int64 INT64; 47 | typedef signed __int64 LONG64; 48 | typedef signed long LONG32; 49 | typedef unsigned char UINT8; 50 | typedef unsigned char BYTE; 51 | typedef unsigned short UINT16; 52 | typedef unsigned short WCHAR; 53 | typedef unsigned int UINT32; 54 | typedef unsigned __int64 UINT64; 55 | typedef unsigned __int64 ULONG64; 56 | typedef unsigned long ULONG32; 57 | typedef float FLOAT32; 58 | typedef double FLOAT64; 59 | typedef struct {unsigned short W[5];} FLOAT80; 60 | typedef struct { __int64 LowPart;__int64 HighPart;} FLOAT128; 61 | typedef double DATE; 62 | typedef signed long HRESULT; 63 | typedef union { struct {unsigned long Lo; long Hi;}; __int64 int64;} CURRENCY; 64 | 65 | 66 | typedef struct _LIST_ENTRY64 // 2 elements, 0x10 bytes (sizeof) 67 | { 68 | /*0x000*/ UINT64 Flink; 69 | /*0x008*/ UINT64 Blink; 70 | }LIST_ENTRY64, *PLIST_ENTRY64; 71 | 72 | typedef struct _DBGKD_GET_VERSION64 { 73 | UINT16 MajorVersion; 74 | UINT16 MinorVersion; 75 | UCHAR ProtocolVersion; 76 | UCHAR KdSecondaryVersion; // Cannot be 'A' for compat with dump header 77 | UINT16 Flags; 78 | UINT16 MachineType; 79 | 80 | // 81 | // Protocol command support descriptions. 82 | // These allow the debugger to automatically 83 | // adapt to different levels of command support 84 | // in different kernels. 85 | // 86 | 87 | // One beyond highest packet type understood, zero based. 88 | UCHAR MaxPacketType; 89 | // One beyond highest state change understood, zero based. 90 | UCHAR MaxStateChange; 91 | // One beyond highest state manipulate message understood, zero based. 92 | UCHAR MaxManipulate; 93 | 94 | // Kind of execution environment the kernel is running in, 95 | // such as a real machine or a simulator. Written back 96 | // by the simulation if one exists. 97 | UCHAR Simulation; 98 | 99 | UINT16 Unused[1]; 100 | 101 | ULONG64 KernBase; 102 | ULONG64 PsLoadedModuleList; 103 | 104 | // 105 | // Components may register a debug data block for use by 106 | // debugger extensions. This is the address of the list head. 107 | // 108 | // There will always be an entry for the debugger. 109 | // 110 | 111 | ULONG64 DebuggerDataList; 112 | 113 | } DBGKD_GET_VERSION64, *PDBGKD_GET_VERSION64; 114 | 115 | 116 | // 117 | // This structure is used by the debugger for all targets 118 | // It is the same size as DBGKD_DATA_HEADER on all systems 119 | // 120 | typedef struct _DBGKD_DEBUG_DATA_HEADER64 { 121 | 122 | // 123 | // Link to other blocks 124 | // 125 | 126 | struct _LIST_ENTRY64 List; 127 | 128 | // 129 | // This is a unique tag to identify the owner of the block. 130 | // If your component only uses one pool tag, use it for this, too. 131 | // 132 | 133 | ULONG32 OwnerTag; 134 | 135 | // 136 | // This must be initialized to the size of the data block, 137 | // including this structure. 138 | // 139 | 140 | ULONG32 Size; 141 | 142 | } DBGKD_DEBUG_DATA_HEADER64, *PDBGKD_DEBUG_DATA_HEADER64; 143 | 144 | 145 | // 146 | // This structure is the same size on all systems. The only field 147 | // which must be translated by the debugger is Header.List. 148 | // 149 | 150 | // 151 | // DO NOT ADD OR REMOVE FIELDS FROM THE MIDDLE OF THIS STRUCTURE!!! 152 | // 153 | // If you remove a field, replace it with an "unused" placeholder. 154 | // Do not reuse fields until there has been enough time for old debuggers 155 | // and extensions to age out. 156 | // 157 | typedef struct _KDDEBUGGER_DATA64 { 158 | 159 | struct _DBGKD_DEBUG_DATA_HEADER64 Header; 160 | 161 | // 162 | // Base address of kernel image 163 | // 164 | 165 | ULONG64 KernBase; 166 | 167 | // 168 | // DbgBreakPointWithStatus is a function which takes an argument 169 | // and hits a breakpoint. This field contains the address of the 170 | // breakpoint instruction. When the debugger sees a breakpoint 171 | // at this address, it may retrieve the argument from the first 172 | // argument register, or on x86 the eax register. 173 | // 174 | 175 | ULONG64 BreakpointWithStatus; // address of breakpoint 176 | 177 | // 178 | // Address of the saved context record during a bugcheck 179 | // 180 | // N.B. This is an automatic in KeBugcheckEx's frame, and 181 | // is only valid after a bugcheck. 182 | // 183 | 184 | ULONG64 SavedContext; 185 | 186 | // 187 | // help for walking stacks with user callbacks: 188 | // 189 | 190 | // 191 | // The address of the thread structure is provided in the 192 | // WAIT_STATE_CHANGE packet. This is the offset from the base of 193 | // the thread structure to the pointer to the kernel stack frame 194 | // for the currently active usermode callback. 195 | // 196 | 197 | UINT16 ThCallbackStack; // offset in thread data 198 | 199 | // 200 | // these values are offsets into that frame: 201 | // 202 | 203 | UINT16 NextCallback; // saved pointer to next callback frame 204 | UINT16 FramePointer; // saved frame pointer 205 | 206 | // 207 | // pad to a quad boundary 208 | // 209 | UINT16 PaeEnabled; 210 | 211 | // 212 | // Address of the kernel callout routine. 213 | // 214 | 215 | ULONG64 KiCallUserMode; // kernel routine 216 | 217 | // 218 | // Address of the usermode entry point for callbacks. 219 | // 220 | 221 | ULONG64 KeUserCallbackDispatcher; // address in ntdll 222 | 223 | 224 | // 225 | // Addresses of various kernel data structures and lists 226 | // that are of interest to the kernel debugger. 227 | // 228 | 229 | ULONG64 PsLoadedModuleList; 230 | ULONG64 PsActiveProcessHead; 231 | ULONG64 PspCidTable; 232 | 233 | ULONG64 ExpSystemResourcesList; 234 | ULONG64 ExpPagedPoolDescriptor; 235 | ULONG64 ExpNumberOfPagedPools; 236 | 237 | ULONG64 KeTimeIncrement; 238 | ULONG64 KeBugCheckCallbackListHead; 239 | ULONG64 KiBugcheckData; 240 | 241 | ULONG64 IopErrorLogListHead; 242 | 243 | ULONG64 ObpRootDirectoryObject; 244 | ULONG64 ObpTypeObjectType; 245 | 246 | ULONG64 MmSystemCacheStart; 247 | ULONG64 MmSystemCacheEnd; 248 | ULONG64 MmSystemCacheWs; 249 | 250 | ULONG64 MmPfnDatabase; 251 | ULONG64 MmSystemPtesStart; 252 | ULONG64 MmSystemPtesEnd; 253 | ULONG64 MmSubsectionBase; 254 | ULONG64 MmNumberOfPagingFiles; 255 | 256 | ULONG64 MmLowestPhysicalPage; 257 | ULONG64 MmHighestPhysicalPage; 258 | ULONG64 MmNumberOfPhysicalPages; 259 | 260 | ULONG64 MmMaximumNonPagedPoolInBytes; 261 | ULONG64 MmNonPagedSystemStart; 262 | ULONG64 MmNonPagedPoolStart; 263 | ULONG64 MmNonPagedPoolEnd; 264 | 265 | ULONG64 MmPagedPoolStart; 266 | ULONG64 MmPagedPoolEnd; 267 | ULONG64 MmPagedPoolInformation; 268 | ULONG64 MmPageSize; 269 | 270 | ULONG64 MmSizeOfPagedPoolInBytes; 271 | 272 | ULONG64 MmTotalCommitLimit; 273 | ULONG64 MmTotalCommittedPages; 274 | ULONG64 MmSharedCommit; 275 | ULONG64 MmDriverCommit; 276 | ULONG64 MmProcessCommit; 277 | ULONG64 MmPagedPoolCommit; 278 | ULONG64 MmExtendedCommit; 279 | 280 | ULONG64 MmZeroedPageListHead; 281 | ULONG64 MmFreePageListHead; 282 | ULONG64 MmStandbyPageListHead; 283 | ULONG64 MmModifiedPageListHead; 284 | ULONG64 MmModifiedNoWritePageListHead; 285 | ULONG64 MmAvailablePages; 286 | ULONG64 MmResidentAvailablePages; 287 | 288 | ULONG64 PoolTrackTable; 289 | ULONG64 NonPagedPoolDescriptor; 290 | 291 | ULONG64 MmHighestUserAddress; 292 | ULONG64 MmSystemRangeStart; 293 | ULONG64 MmUserProbeAddress; 294 | 295 | ULONG64 KdPrintCircularBuffer; 296 | ULONG64 KdPrintCircularBufferEnd; 297 | ULONG64 KdPrintWritePointer; 298 | ULONG64 KdPrintRolloverCount; 299 | 300 | ULONG64 MmLoadedUserImageList; 301 | 302 | // NT 5.1 Addition 303 | 304 | ULONG64 NtBuildLab; 305 | ULONG64 KiNormalSystemCall; 306 | 307 | // NT 5.0 hotfix addition 308 | 309 | ULONG64 KiProcessorBlock; 310 | ULONG64 MmUnloadedDrivers; 311 | ULONG64 MmLastUnloadedDriver; 312 | ULONG64 MmTriageActionTaken; 313 | ULONG64 MmSpecialPoolTag; 314 | ULONG64 KernelVerifier; 315 | ULONG64 MmVerifierData; 316 | ULONG64 MmAllocatedNonPagedPool; 317 | ULONG64 MmPeakCommitment; 318 | ULONG64 MmTotalCommitLimitMaximum; 319 | ULONG64 CmNtCSDVersion; 320 | 321 | // NT 5.1 Addition 322 | 323 | ULONG64 MmPhysicalMemoryBlock; 324 | ULONG64 MmSessionBase; 325 | ULONG64 MmSessionSize; 326 | ULONG64 MmSystemParentTablePage; 327 | 328 | // Server 2003 addition 329 | 330 | ULONG64 MmVirtualTranslationBase; 331 | 332 | UINT16 OffsetKThreadNextProcessor; 333 | UINT16 OffsetKThreadTeb; 334 | UINT16 OffsetKThreadKernelStack; 335 | UINT16 OffsetKThreadInitialStack; 336 | 337 | UINT16 OffsetKThreadApcProcess; 338 | UINT16 OffsetKThreadState; 339 | UINT16 OffsetKThreadBStore; 340 | UINT16 OffsetKThreadBStoreLimit; 341 | 342 | UINT16 SizeEProcess; 343 | UINT16 OffsetEprocessPeb; 344 | UINT16 OffsetEprocessParentCID; 345 | UINT16 OffsetEprocessDirectoryTableBase; 346 | 347 | UINT16 SizePrcb; 348 | UINT16 OffsetPrcbDpcRoutine; 349 | UINT16 OffsetPrcbCurrentThread; 350 | UINT16 OffsetPrcbMhz; 351 | 352 | UINT16 OffsetPrcbCpuType; 353 | UINT16 OffsetPrcbVendorString; 354 | UINT16 OffsetPrcbProcStateContext; 355 | UINT16 OffsetPrcbNumber; 356 | 357 | UINT16 SizeEThread; 358 | 359 | ULONG64 KdPrintCircularBufferPtr; 360 | ULONG64 KdPrintBufferSize; 361 | 362 | ULONG64 KeLoaderBlock; 363 | 364 | UINT16 SizePcr; 365 | UINT16 OffsetPcrSelfPcr; 366 | UINT16 OffsetPcrCurrentPrcb; 367 | UINT16 OffsetPcrContainedPrcb; 368 | 369 | UINT16 OffsetPcrInitialBStore; 370 | UINT16 OffsetPcrBStoreLimit; 371 | UINT16 OffsetPcrInitialStack; 372 | UINT16 OffsetPcrStackLimit; 373 | 374 | UINT16 OffsetPrcbPcrPage; 375 | UINT16 OffsetPrcbProcStateSpecialReg; 376 | UINT16 GdtR0Code; 377 | UINT16 GdtR0Data; 378 | 379 | UINT16 GdtR0Pcr; 380 | UINT16 GdtR3Code; 381 | UINT16 GdtR3Data; 382 | UINT16 GdtR3Teb; 383 | 384 | UINT16 GdtLdt; 385 | UINT16 GdtTss; 386 | UINT16 Gdt64R3CmCode; 387 | UINT16 Gdt64R3CmTeb; 388 | 389 | ULONG64 IopNumTriageDumpDataBlocks; 390 | ULONG64 IopTriageDumpDataBlocks; 391 | 392 | // Longhorn addition 393 | 394 | ULONG64 VfCrashDataBlock; 395 | ULONG64 MmBadPagesDetected; 396 | ULONG64 MmZeroedPageSingleBitErrorsDetected; 397 | 398 | 399 | } KDDEBUGGER_DATA64, *PKDDEBUGGER_DATA64; 400 | 401 | 402 | -------------------------------------------------------------------------------- /src/metasm/virtdbg.rb: -------------------------------------------------------------------------------- 1 | # This file is part of Virtdbg 2 | # Copyright (C) 2010-2011 Damien AUMAITRE 3 | # 4 | # Licence is GPLv3, see LICENCE.txt in the top-level directory 5 | 6 | module VirtDbg 7 | VIRTDBGDIR = File.dirname(__FILE__) 8 | # add it to the ruby library path 9 | $: << VIRTDBGDIR 10 | end 11 | 12 | %w[forensic1394 virtdbg util main system].each { |f| 13 | require File.join('virtdbg', f) 14 | } 15 | 16 | -------------------------------------------------------------------------------- /src/metasm/virtdbg/forensic1394.rb: -------------------------------------------------------------------------------- 1 | # This file is part of Virtdbg 2 | # Copyright (C) 2010-2011 Damien AUMAITRE 3 | # 4 | # Licence is GPLv3, see LICENCE.txt in the top-level directory 5 | 6 | 7 | require 'metasm' 8 | require 'metasm/dynldr' 9 | 10 | include Metasm 11 | 12 | module VirtDbg 13 | 14 | class Forensic1394 < Metasm::DynLdr 15 | new_api_c File.read(File.join(VIRTDBGDIR, "inc", "forensic1394.h")), 16 | "libforensic1394.so" 17 | end 18 | 19 | # FIXME : need to handle 32 bits ruby 20 | 21 | class Bus 22 | def initialize 23 | @bus_ptr = Forensic1394.forensic1394_alloc() 24 | # ObjectSpace.define_finalizer(self, self.class.finalize(@bus_ptr)) 25 | end 26 | 27 | def self.finalize(bus_ptr) 28 | proc {Forensic1394.forensic1394_destroy(bus_ptr)} 29 | end 30 | 31 | def enable_sbp2 32 | Forensic1394.forensic1394_enable_sbp2(@bus_ptr) 33 | end 34 | 35 | def devices 36 | # Query the list of devices attached to the system 37 | ndev_ptr = (0.chr)*8 38 | devlist = Forensic1394.forensic1394_get_devices(@bus_ptr, ndev_ptr, 0) 39 | ndev_value = ndev_ptr.unpack('Q').first 40 | if ndev_value < 0 41 | puts "error: can't get devices" 42 | return nil 43 | end 44 | devices = [] 45 | ndev_value.times {|i| 46 | dev_ptr = Forensic1394.memory_read_int(devlist+i*8) 47 | devices << Device.new(self, dev_ptr) 48 | } 49 | devices 50 | end 51 | end 52 | 53 | class Device 54 | 55 | attr_accessor :nodeid, :guid, :product_name, :product_id, :vendor_name, :vendor_id, :request_size, :csr 56 | 57 | def initialize(bus, dev_ptr) 58 | @bus = bus 59 | @dev_ptr = dev_ptr 60 | 61 | @nodeid = Forensic1394.forensic1394_get_device_nodeid(@dev_ptr) 62 | @guid = Forensic1394.forensic1394_get_device_guid(@dev_ptr) 63 | @product_name = Forensic1394.forensic1394_get_device_product_name(@dev_ptr) 64 | @product_name = Forensic1394.memory_read_strz(@product_name) 65 | @product_id = Forensic1394.forensic1394_get_device_product_id(@dev_ptr) 66 | @vendor_name = Forensic1394.forensic1394_get_device_vendor_name(@dev_ptr) 67 | @vendor_name = Forensic1394.memory_read_strz(@vendor_name) 68 | @vendor_id = Forensic1394.forensic1394_get_device_vendor_id(@dev_ptr) 69 | @request_size = Forensic1394.forensic1394_get_device_request_size(@dev_ptr) 70 | 71 | @csr = (0.chr)*1024 72 | Forensic1394.forensic1394_get_device_csr(@dev_ptr, @csr) 73 | # ObjectSpace.define_finalizer(self, self.class.finalize(@dev_ptr)) 74 | end 75 | 76 | def open 77 | Forensic1394.forensic1394_open_device(@dev_ptr) 78 | end 79 | 80 | def close 81 | Forensic1394.forensic1394_close_device(@dev_ptr) 82 | end 83 | 84 | def internal_read(address, size) 85 | buf = (0.chr)*size 86 | Forensic1394.forensic1394_read_device(@dev_ptr, address, size, buf) 87 | buf 88 | end 89 | 90 | def internal_read_v(req) 91 | buffers = [] 92 | creq_size = Forensic1394.alloc_c_struct("forensic1394_req").length 93 | 94 | creq = req.map {|addr, size| 95 | creq = Forensic1394.alloc_c_struct("forensic1394_req") 96 | creq.addr = addr 97 | creq.len = size 98 | buf = (0.chr)*size 99 | buffers << buf 100 | creq.buf = buf 101 | creq 102 | } 103 | 104 | ptr = tmp = Forensic1394.memory_alloc(req.size*creq_size) 105 | creq.each { |s| Forensic1394.memory_write(tmp, s.str) ; tmp += s.length } 106 | Forensic1394.forensic1394_read_device_v(@dev_ptr, ptr, req.size) 107 | buffers 108 | end 109 | 110 | def read(address, size) 111 | #FIXME handle read requests > request_size 112 | end 113 | 114 | 115 | def internal_write(address, data) 116 | Forensic1394.forensic1394_write_device(@dev_ptr, address, data.size, data) 117 | end 118 | 119 | def internal_write_v(req) 120 | creq_size = Forensic1394.alloc_c_struct("forensic1394_req").length 121 | creq = req.map {|addr, data| 122 | creq = Forensic1394.alloc_c_struct("forensic1394_req") 123 | creq.addr = addr 124 | creq.buf = data 125 | creq.len = data.size 126 | creq 127 | } 128 | ptr = tmp = Forensic1394.memory_alloc(req.size*creq_size) 129 | creq.each { |s| Forensic1394.memory_write(tmp, s.str) ; tmp += s.length } 130 | Forensic1394.forensic1394_write_device_v(@dev_ptr, ptr, req.size) 131 | end 132 | 133 | def write(address, data) 134 | #FIXME handle write requests > request_size 135 | end 136 | 137 | def self.finalize(dev_ptr) 138 | proc {Forensic1394.forensic1394_destroy(dev_ptr)} 139 | end 140 | end 141 | 142 | class FireWireMem < VirtualString 143 | def initialize(device, addr=0, length=nil) 144 | @device = device 145 | length ||= 1<<32 146 | super(addr, length) 147 | @pagecache_len = 128 148 | @pagelength = @device.request_size 149 | end 150 | 151 | def dup(addr=@addr_start, len=@length) 152 | self.class.new(@device, addr, len) 153 | end 154 | 155 | def rewrite_at(addr, data) 156 | # puts "1394: rewrite @ #{addr.to_s(16)} #{data.length.to_s(16)} bytes" 157 | @device.internal_write(addr, data) 158 | end 159 | 160 | def get_page(addr, len=@pagelength) 161 | # puts "1394: get page @ #{addr.to_s(16)}, #{len} bytes" 162 | buf = @device.internal_read(addr, len) 163 | buf 164 | end 165 | 166 | def close 167 | @dev.close 168 | end 169 | 170 | def hexdump(addr, size) 171 | @device.internal_read(addr, size).hexdump(:fmt => ['c','a'], :noend => true) 172 | end 173 | end 174 | 175 | end 176 | -------------------------------------------------------------------------------- /src/metasm/virtdbg/main.rb: -------------------------------------------------------------------------------- 1 | # This file is part of Virtdbg 2 | # Copyright (C) 2010-2011 Damien AUMAITRE 3 | # 4 | # Licence is GPLv3, see LICENCE.txt in the top-level directory 5 | 6 | require 'metasm' 7 | require 'metasm/dynldr' 8 | 9 | include Metasm 10 | 11 | module VirtDbg 12 | 13 | class VirtDbgMem < VirtualString 14 | def initialize(impl, addr=0, length=nil) 15 | @impl = impl 16 | length ||= 1<<64 17 | super(addr, length) 18 | @pagecache_len = 128 19 | @pagelength = 0x400 20 | end 21 | 22 | def dup(addr=@addr_start, len=@length) 23 | self.class.new(@impl, addr, len) 24 | end 25 | 26 | def rewrite_at(addr, data) 27 | # puts "virtdbgmem: rewrite @ #{addr.to_s(16)} #{data.length.to_s(16)} bytes" 28 | @impl.write_virtual_memory(addr, data) 29 | end 30 | 31 | def get_page(addr, len=@pagelength) 32 | # puts "virtdbgmem: get page @ #{addr.to_s(16)}, #{len} bytes" 33 | buf = @impl.read_virtual_memory(addr, len) 34 | buf 35 | end 36 | 37 | def hexdump(addr, size) 38 | get_page(addr, size).hexdump(:fmt => ['c','a'], :noend => true) 39 | end 40 | end 41 | 42 | class VirtDbg < Debugger 43 | def initialize(impl) 44 | @impl = impl 45 | @cpu = X86_64.new 46 | @memory = VirtDbgMem.new(impl) 47 | @context = {} 48 | @system = nil 49 | super() 50 | @info = nil 51 | end 52 | 53 | def state 54 | @impl.state 55 | end 56 | 57 | def state=(state) 58 | @impl.state = state 59 | end 60 | 61 | def get_reg_value(reg) 62 | if @context.empty? 63 | context = @impl.get_context 64 | return 0 if not context 65 | @context = context 66 | end 67 | 68 | @context[reg] 69 | end 70 | 71 | def set_reg_value(reg, val) 72 | @context[reg] = val 73 | end 74 | 75 | def invalidate 76 | if not @context.empty? 77 | @impl.set_context @context 78 | end 79 | @memory.invalidate 80 | @context.clear 81 | super() 82 | end 83 | 84 | def do_continue(*a) 85 | invalidate 86 | @impl.continue 87 | @info = nil 88 | end 89 | 90 | def do_singlestep(*a) 91 | invalidate 92 | @impl.singlestep 93 | @info = "singlestep" 94 | end 95 | 96 | def break 97 | @impl.breakin 98 | end 99 | 100 | # non blocking 101 | def do_check_target 102 | invalidate 103 | packet = @impl.recv_packet 104 | if packet and packet.kind_of? StateChangePacket 105 | @impl.state = :stopped 106 | @info = "got exception #{packet.exception}" 107 | else 108 | puts "do check, got #{packet.inspect}" if packet 109 | end 110 | end 111 | 112 | # blocking 113 | def do_wait_target 114 | loop do 115 | do_check_target 116 | break if @impl.state == :stopped 117 | end 118 | end 119 | 120 | def bpx(addr, *a) 121 | hwbp(addr, :x, 1, *a) 122 | end 123 | 124 | def need_stepover(di) 125 | di and ((di.instruction.prefix and di.instruction.prefix[:rep]) or di.opcode.props[:saveip]) 126 | end 127 | 128 | def enable_bp(addr) 129 | return if not b = @breakpoint[addr] 130 | case b.type 131 | when :hw 132 | @cpu.dbg_enable_bp(self, addr, b) 133 | end 134 | b.state = :active 135 | end 136 | 137 | def disable_bp(addr) 138 | return if not b = @breakpoint[addr] 139 | @cpu.dbg_disable_bp(self, addr, b) 140 | b.state = :inactive 141 | end 142 | 143 | def dumplog(arg=nil) 144 | puts @impl.dumplog 145 | end 146 | 147 | def handshake(arg=nil) 148 | puts @impl.handshake 149 | end 150 | 151 | def loadsyms(addr, name="%08x"%addr.to_i) 152 | return if not peek = @memory.get_page(addr, 4) 153 | if peek[0, 2] == "MZ" and @memory[addr+@memory[addr+0x3c,4].unpack('V').first, 4] == "PE\0\0" 154 | cls = LoadedPE 155 | else return 156 | end 157 | 158 | @loadedsyms ||= {} 159 | return if @loadedsyms[name] 160 | @loadedsyms[name] = true 161 | 162 | begin 163 | e = cls.load @memory[addr, 0x1000_0000] 164 | e.load_address = addr 165 | e.decode_header 166 | e.decode_exports 167 | rescue 168 | @modulemap[addr.to_s(16)] = [addr, addr+0x1000] 169 | return 170 | end 171 | 172 | if n = e.module_name and n != name 173 | name = n 174 | return if @loadedsyms[name] 175 | @loadedsyms[name] = true 176 | end 177 | 178 | @modulemap[name] = [addr, addr+e.module_size] 179 | 180 | sl = @symbols.length 181 | e.module_symbols.each { |n_, a, l| 182 | a += addr 183 | @disassembler.set_label_at(a, n_, false) 184 | @symbols[a] = n_ 185 | if l and l > 1; @symbols_len[a] = l 186 | else @symbols_len.delete a # we may overwrite an existing symbol, keep len in sync 187 | end 188 | } 189 | puts "loaded #{@symbols.length - sl} symbols from #{name}" 190 | true 191 | end 192 | 193 | def loadkernel(arg=nil) 194 | kernelbase = @impl.area.KernelBase 195 | gui.parent_widget.mem.focus_addr kernelbase 196 | loadsyms kernelbase 197 | end 198 | 199 | def info(arg=nil) 200 | # dumping various info 201 | end 202 | 203 | def system(arg=nil) 204 | puts "getting operating system..." 205 | kernelbase = @impl.area.KernelBase 206 | @system = System.new(@memory, kernelbase) 207 | puts "done" 208 | end 209 | 210 | def idt(arg=nil) 211 | puts "dumping idt ! na kidding !" 212 | end 213 | 214 | def processes(arg=nil) 215 | # @statusline = "listing processes, please wait" 216 | # redraw 217 | # Gui.main_iter 218 | if not @system 219 | # @statusline = "getting system" 220 | # redraw 221 | # Gui.main_iter 222 | system 223 | end 224 | @system.processes {|p| puts "#{p.name} (#{p.pid})"} 225 | end 226 | 227 | def modules(arg=nil) 228 | if not @system 229 | system 230 | end 231 | @system.modules {|m| puts "#{m.name} 0x#{m.base.to_s(16)} 0x#{m.size.to_s(16)} 0x#{m.entrypoint.to_s(16)}"} 232 | end 233 | 234 | def ui_command_setup(ui) 235 | ui.new_command('idt', 'dump idt') { |arg| idt arg } 236 | ui.new_command('dumplog', 'dump log') { |arg| dumplog arg } 237 | ui.new_command('handshake', 'get a new client id') { |arg| handshake arg } 238 | ui.new_command('loadkernel', 'load kernel symbols') { |arg| loadkernel arg } 239 | ui.new_command('processes', 'list processes') { |arg| processes arg } 240 | ui.new_command('modules', 'list modules') { |arg| modules arg } 241 | end 242 | 243 | end 244 | 245 | end 246 | -------------------------------------------------------------------------------- /src/metasm/virtdbg/system.rb: -------------------------------------------------------------------------------- 1 | # This file is part of Virtdbg 2 | # Copyright (C) 2010-2011 Damien AUMAITRE 3 | # 4 | # Licence is GPLv3, see LICENCE.txt in the top-level directory 5 | 6 | require 'metasm' 7 | require 'metasm/dynldr' 8 | require 'iconv' 9 | 10 | class String 11 | def utf16_to_iso 12 | converter = Iconv.new('ISO-8859-1//IGNORE//TRANSLIT', 'UTF-16') 13 | converter.iconv(self) 14 | end 15 | end 16 | 17 | include Metasm 18 | 19 | 20 | module VirtDbg 21 | 22 | # class WindowsAPI < DynLdr 23 | # new_api_c File.read(File.join(VIRTDBGDIR, "inc", "ntoskrnl.exe_F8E2A8B5C9B74BF4A6E4A48F18009994.h")) 24 | # end 25 | 26 | # class WinDbgAPI < DynLdr 27 | # new_api_c File.read(File.join(VIRTDBGDIR, "inc", "wdbgexts.h")) 28 | # end 29 | 30 | class System 31 | 32 | attr_accessor :mem, :ctypes 33 | def initialize(mem, addr) 34 | @mem = mem 35 | @kernelbase = addr 36 | 37 | puts "kernel @ 0x%x" % addr 38 | 39 | pe = LoadedPE.load @mem[addr, 0x1000_0000] 40 | pe.load_address = addr 41 | pe.decode_header 42 | pe.decode_debug 43 | @kernel = pe 44 | 45 | filename = pe.debug[0].data.pdbfilename 46 | guid = pe.debug[0].data.guid 47 | guid = '%x%x%x%x%x' % guid.unpack('VvvNN') 48 | age = pe.debug[0].data.age 49 | path = "#{filename}_#{guid}#{age}.h" 50 | @wdbgexts = Class.new(DynLdr) 51 | @wdbgexts.cp.llp64 52 | puts "loading wdbgexts header..." 53 | @wdbgexts.new_api_c File.read(File.join(VIRTDBGDIR, "inc", "wdbgexts.h")) 54 | @ctypes = Class.new(DynLdr) 55 | @ctypes.cp.llp64 56 | puts "loading #{path} header..." 57 | @ctypes.new_api_c File.read(File.join(VIRTDBGDIR, "inc", path)) 58 | offset = 0x1e9070 # FIXME export this in hypervisor find KDBG sig 59 | @debugdata = @wdbgexts.decode_c_struct("KDDEBUGGER_DATA64", @mem, addr+offset) 60 | end 61 | 62 | def offsetof(structname, fieldname) 63 | st = @ctypes.cp.find_c_struct(structname) 64 | st.offsetof(nil, fieldname) 65 | end 66 | 67 | def decode_c_ptr(addr) 68 | @ctypes.decode_c_ary('void*', 1, @mem, addr) 69 | end 70 | 71 | def processes 72 | addr = decode_c_ptr(@debugdata.PsActiveProcessHead)[0] 73 | offset = offsetof("EPROCESS", "ActiveProcessLinks") 74 | first = Process.new(self, addr-offset) 75 | current = first 76 | while 42 77 | n = current.next 78 | break if n.address == first.address 79 | yield current 80 | current = n 81 | end 82 | end 83 | 84 | def modules 85 | addr = decode_c_ptr(@debugdata.PsLoadedModuleList)[0] 86 | first = Module.new(self, addr) 87 | current = first 88 | while 42 89 | n = current.next 90 | break if n.address == first.address 91 | yield current 92 | current = n 93 | end 94 | end 95 | 96 | end 97 | 98 | class Process 99 | 100 | attr_accessor :address 101 | 102 | def initialize(system, address) 103 | @system = system 104 | @address = address 105 | @offset = system.offsetof("EPROCESS", "ActiveProcessLinks") 106 | @eproc = system.ctypes.decode_c_struct("EPROCESS", system.mem, address) 107 | puts @eproc.to_s 108 | end 109 | 110 | def cr3 111 | @eproc.Pcb.DirectoryTableBase 112 | end 113 | 114 | def pid 115 | @eproc.UniqueProcessId 116 | end 117 | 118 | def name 119 | @eproc.ImageFileName.to_array.pack('C*').strip 120 | end 121 | 122 | def processlinks 123 | @eproc.ActiveProcessLinks 124 | end 125 | 126 | def next 127 | address = @eproc.ActiveProcessLinks.Flink 128 | puts "address=%x" % address 129 | puts "offset=%x" % @offset 130 | self.class.new(@system, address-@offset) 131 | end 132 | 133 | end 134 | 135 | class Module 136 | 137 | attr_accessor :address 138 | 139 | def initialize(system, address) 140 | @system = system 141 | @address = address 142 | @entry = system.ctypes.decode_c_struct("LDR_DATA_TABLE_ENTRY", system.mem, address) 143 | puts @entry.to_s 144 | end 145 | 146 | def next 147 | addr = @entry.InLoadOrderLinks.Flink 148 | self.class.new(@system, addr) 149 | end 150 | 151 | def fullname 152 | ptr = @entry.FullDllName.Buffer 153 | len = @entry.FullDllName.Length 154 | fullname = @system.mem[ptr,len] 155 | fullname.utf16_to_iso 156 | end 157 | 158 | def name 159 | ptr = @entry.BaseDllName.Buffer 160 | len = @entry.BaseDllName.Length 161 | name = @system.mem[ptr,len] 162 | name.utf16_to_iso 163 | end 164 | 165 | def base 166 | base = @entry.DllBase 167 | base 168 | end 169 | 170 | def size 171 | size = @entry.SizeOfImage 172 | size 173 | end 174 | 175 | def entrypoint 176 | entrypoint = @entry.EntryPoint 177 | entrypoint 178 | end 179 | 180 | end 181 | 182 | end 183 | 184 | -------------------------------------------------------------------------------- /src/metasm/virtdbg/util.rb: -------------------------------------------------------------------------------- 1 | # ripped from metasm/misc 2 | class IO 3 | def hexdump(ctx={}) 4 | ctx[:noend] = true 5 | while buf = read(512) and not buf.empty? 6 | buf.hexdump(ctx) 7 | end 8 | ctx.delete :noend 9 | ''.hexdump(ctx) 10 | end 11 | end 12 | 13 | class String 14 | def hexdump(ctx={}) 15 | fmt = ctx[:fmt] ||= ['c', 'd', 'a'] 16 | ctx[:pos] ||= 0 17 | ctx[:linelen] ||= 16 18 | scan(/.{1,#{ctx[:linelen]}}/m) { |s| 19 | if s != ctx[:lastline] 20 | ctx[:lastdup] = false 21 | print '%04x ' % ctx[:pos] 22 | print s.unpack('C*').map { |b| '%02x' % b }.join(' ').ljust(3*16-1) + ' ' if fmt.include? 'c' 23 | print s.unpack('v*').map { |b| '%04x' % b }.join(' ').ljust(5*8-1) + ' ' if fmt.include? 'w' 24 | print s.unpack('L*').map { |b| '%08x' % b }.join(' ').ljust(9*4-1) + ' ' if fmt.include? 'd' 25 | print s.tr("\0-\x1f\x7f-\xff", '.') if fmt.include? 'a' 26 | puts 27 | elsif not ctx[:lastdup] 28 | ctx[:lastdup] = true 29 | puts '*' 30 | end 31 | ctx[:lastline] = s 32 | ctx[:pos] += s.length 33 | } 34 | puts '%04x' % ctx[:pos] if not ctx[:noend] 35 | end 36 | end 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/metasm/virtdbg/virtdbg.rb: -------------------------------------------------------------------------------- 1 | # This file is part of Virtdbg 2 | # Copyright (C) 2010-2011 Damien AUMAITRE 3 | # 4 | # Licence is GPLv3, see LICENCE.txt in the top-level directory 5 | 6 | require 'metasm' 7 | require 'metasm/dynldr' 8 | 9 | include Metasm 10 | 11 | def calc_checksum(data) 12 | data.unpack('C*').inject(0) { |sum, byte| sum+byte } 13 | end 14 | 15 | module VirtDbg 16 | 17 | class VirtDbgAPI < DynLdr 18 | new_api_c File.read(File.join(VIRTDBGDIR, "inc", "virtdbg.h")) 19 | end 20 | 21 | class VirtDbgPacket 22 | attr_accessor :header, :data1, :data2 23 | def initialize 24 | @header = VirtDbgAPI.alloc_c_struct("PACKET_HEADER") 25 | @header.Magic = VirtDbgAPI::PACKET_MAGIC 26 | @data1 = nil 27 | @data2 = nil 28 | end 29 | 30 | def data 31 | data = @data1 ? @data1.str[@data1.stroff, @data1.length] : "" 32 | if @data2.kind_of? String 33 | data << @data2 34 | elsif @data2 35 | data << @data2.str[@data2.stroff, @data2.length] 36 | end 37 | data 38 | end 39 | 40 | def encode 41 | fixup 42 | raw = @header.str[@header.stroff, @header.length] 43 | raw << data 44 | raw 45 | end 46 | 47 | def to_s 48 | puts @header.to_s 49 | puts @data1.to_s if @data1 50 | puts @data2.to_s if @data2 and not @data2.kind_of? String 51 | end 52 | 53 | def fixup 54 | @header.Checksum = calc_checksum(data) 55 | @header.Size = (@data1 ? @data1.length : 0) + (@data2 ? @data2.length : 0) 56 | end 57 | end 58 | 59 | class BreakinPacket < VirtDbgPacket 60 | def initialize(cr3=0) 61 | super() 62 | @header.Type = VirtDbgAPI::PACKET_TYPE_BREAKIN 63 | @data1 = VirtDbgAPI.alloc_c_struct("BREAKIN_PACKET") 64 | @data1.Cr3 = cr3 65 | end 66 | end 67 | 68 | class ResetPacket < VirtDbgPacket 69 | def initialize 70 | super() 71 | @header.Type = VirtDbgAPI::PACKET_TYPE_RESET 72 | end 73 | end 74 | 75 | class AckPacket < VirtDbgPacket 76 | def initialize 77 | super() 78 | @header.Type = VirtDbgAPI::PACKET_TYPE_ACK 79 | end 80 | end 81 | 82 | class ContinuePacket < VirtDbgPacket 83 | def initialize(status=0) 84 | super() 85 | @header.Type = VirtDbgAPI::PACKET_TYPE_CONTINUE 86 | @data1 = VirtDbgAPI.alloc_c_struct("CONTINUE_PACKET") 87 | @data1.Status = status 88 | end 89 | end 90 | 91 | class ManipulateStatePacket < VirtDbgPacket 92 | def initialize 93 | super() 94 | @header.Type = VirtDbgAPI::PACKET_TYPE_MANIPULATE_STATE 95 | @data1 = VirtDbgAPI.alloc_c_struct("MANIPULATE_STATE_PACKET") 96 | end 97 | 98 | def error 99 | @data1.Error 100 | end 101 | end 102 | 103 | class ReadVirtualMemoryPacket < ManipulateStatePacket 104 | def initialize(address=0, size=0) 105 | super() 106 | @data1.ApiNumber = VirtDbgAPI::READ_VIRTUAL_MEMORY_API 107 | @data1.ReadVirtualMemory.Address = address 108 | @data1.ReadVirtualMemory.Size = size 109 | end 110 | end 111 | 112 | class WriteVirtualMemoryPacket < ManipulateStatePacket 113 | def initialize(address=0, data="") 114 | super() 115 | @data1.ApiNumber = VirtDbgAPI::WRITE_VIRTUAL_MEMORY_API 116 | @data1.WriteVirtualMemory.Address = address 117 | @data1.WriteVirtualMemory.Size = data.size 118 | @data2 = data 119 | end 120 | end 121 | 122 | class GetContextPacket < ManipulateStatePacket 123 | def initialize 124 | super() 125 | @data1.ApiNumber = VirtDbgAPI::GET_CONTEXT_API 126 | @data2 = VirtDbgAPI.alloc_c_struct("DEBUG_CONTEXT") 127 | end 128 | end 129 | 130 | class SetContextPacket < ManipulateStatePacket 131 | def initialize 132 | super() 133 | @data1.ApiNumber = VirtDbgAPI::SET_CONTEXT_API 134 | @data2 = VirtDbgAPI.alloc_c_struct("DEBUG_CONTEXT") 135 | end 136 | end 137 | 138 | class StateChangePacket < VirtDbgPacket 139 | def initialize 140 | super() 141 | @header.Type = VirtDbgAPI::PACKET_TYPE_STATE_CHANGE 142 | @data1 = VirtDbgAPI.alloc_c_struct("STATE_CHANGE_PACKET") 143 | end 144 | 145 | def exception 146 | @data1.Exception 147 | end 148 | end 149 | 150 | PAGE_SIZE = 0x1000 151 | MAX_PFN = 0x80000 152 | # 7c000 153 | MIN_PFN = 0 154 | 155 | class VirtDbgImpl 156 | attr_accessor :mem, :area, :state, :clientid 157 | def initialize(mem, max_pfn=MAX_PFN) 158 | @mem = mem 159 | @area = nil 160 | @lastid = 0 161 | @clientid = 0 162 | @id = VirtDbgAPI::INITIAL_ID 163 | @attached = false 164 | @unexpected_packets = [] 165 | @state = :running 166 | @max_pfn = max_pfn 167 | end 168 | 169 | def new_clientid 170 | rand(0x100000) 171 | end 172 | 173 | def setup 174 | result = find_control_area 175 | if result 176 | handshake 177 | return true 178 | else 179 | return false 180 | end 181 | end 182 | 183 | def send_area 184 | @area.RecvArea.QuadPart if @area 185 | end 186 | 187 | def recv_area 188 | @area.SendArea.QuadPart if @area 189 | end 190 | 191 | def find_control_area 192 | puts "searching control area..." 193 | magic = [VirtDbgAPI::CONTROL_AREA_MAGIC1, 194 | VirtDbgAPI::CONTROL_AREA_MAGIC2].pack("LL") 195 | 196 | pfn = @max_pfn.downto(0).find {|i| 197 | header = @mem[i*0x1000, 8] 198 | header == magic } 199 | 200 | if not pfn 201 | puts "can't find control area, aborting" 202 | return false 203 | end 204 | 205 | control_area_paddr = pfn*PAGE_SIZE 206 | puts "found control area @ #{control_area_paddr.to_s(16)}" 207 | @area = VirtDbgAPI.decode_c_struct('VIRTDBG_CONTROL_AREA', 208 | @mem, control_area_paddr) 209 | 210 | # @send_area = @area.recvarea.quadpart 211 | # @recv_area = @area.sendarea.quadpart 212 | puts "send_area @ #{self.send_area.to_s(16)}" 213 | puts "recv_area @ #{self.recv_area.to_s(16)}" 214 | true 215 | end 216 | 217 | def handshake 218 | @clientid = new_clientid 219 | @lastid = 0 220 | @area.ClientId = @clientid 221 | start = Time.now 222 | while @area.ServerId != @clientid 223 | @mem.invalidate 224 | if Time.now-start > 10.0 225 | puts "can't make handshake in 10s, aborting" 226 | return false 227 | end 228 | end 229 | @attached = true 230 | puts "handshake done (client id 0x#{@clientid.to_s(16)})" 231 | return true 232 | end 233 | 234 | def dumplog 235 | @mem.invalidate 236 | @mem[@area.LogBuffer.QuadPart,2048]+@mem[@area.LogBuffer.QuadPart+2048,2048] 237 | end 238 | 239 | def send_packet_internal(packet) 240 | packet.header.ClientId = @clientid 241 | packet.header.Id = @id 242 | packet.fixup 243 | data = packet.encode 244 | @mem[self.send_area, data.length] = data 245 | @id += 1 246 | data.length 247 | end 248 | 249 | def send_packet(packet) 250 | return false if not @attached 251 | start = Time.now 252 | length = send_packet_internal(packet) 253 | while @area.LastClientId != packet.header.Id 254 | @mem.invalidate 255 | return false if Time.now-start > 2.0 256 | end 257 | true 258 | end 259 | 260 | def dispatch_packet(packet) 261 | @unexpected_packets << packet if packet 262 | puts "got an unexpected packet #{packet.inspect}" if packet 263 | end 264 | 265 | def recv_packet_with_type(type) 266 | packet = nil 267 | start = Time.now 268 | loop do 269 | packet = recv_packet 270 | break if packet.kind_of? type 271 | break if Time.now-start > 2.0 272 | dispatch_packet packet 273 | end 274 | packet 275 | end 276 | 277 | def recv_packet 278 | return if not @attached 279 | packet = nil 280 | @mem.invalidate 281 | packet = recv_packet_internal 282 | packet 283 | end 284 | 285 | def recv_packet_internal 286 | data = @mem[self.recv_area, VirtDbgAPI::HEADER_SIZE] 287 | header = VirtDbgAPI.decode_c_struct('PACKET_HEADER', data, 0) 288 | 289 | if header.Magic != VirtDbgAPI::PACKET_MAGIC 290 | # puts "no magic number in header" 291 | return 292 | end 293 | 294 | if not (0..VirtDbgAPI::MAX_PACKET_SIZE).cover? header.Size 295 | # puts "packet too big" 296 | return 297 | end 298 | 299 | if header.Id <= @lastid 300 | # puts "not a new packet" 301 | return 302 | end 303 | 304 | packet_size = VirtDbgAPI::HEADER_SIZE+header.Size 305 | 306 | if header.Size > 0 307 | body = @mem[self.recv_area+VirtDbgAPI::HEADER_SIZE, header.Size] 308 | data << body 309 | 310 | sum = calc_checksum(body) 311 | if sum != header.Checksum 312 | puts "bad checksum, expected #{sum.to_s(16)}, got #{header.Checksum.to_s(16)}" 313 | return 314 | end 315 | end 316 | 317 | case header.Type 318 | when VirtDbgAPI::PACKET_TYPE_RESET 319 | packet = ResetPacket.new 320 | when VirtDbgAPI::PACKET_TYPE_MANIPULATE_STATE 321 | data1 = VirtDbgAPI.decode_c_struct('MANIPULATE_STATE_PACKET', 322 | data, VirtDbgAPI::HEADER_SIZE) 323 | case data1.ApiNumber 324 | when VirtDbgAPI::READ_VIRTUAL_MEMORY_API 325 | packet = ReadVirtualMemoryPacket.new 326 | offset = header.length+data1.length 327 | size = header.Size-data1.length 328 | # puts "offset=0x#{offset.to_s(16)}, size=0x#{size.to_s(16)}" 329 | data2 = data[offset, size] 330 | packet.data2 = data2 331 | 332 | when VirtDbgAPI::WRITE_VIRTUAL_MEMORY_API 333 | packet = WriteVirtualMemoryPacket.new 334 | when VirtDbgAPI::GET_CONTEXT_API 335 | packet = GetContextPacket.new 336 | offset = header.length+data1.length 337 | data2 = VirtDbgAPI.decode_c_struct("DEBUG_CONTEXT", 338 | data, offset) 339 | packet.data2 = data2 340 | 341 | when VirtDbgAPI::SET_CONTEXT_API 342 | packet = SetContextPacket.new 343 | else 344 | puts "invalid api number" 345 | return 346 | end 347 | 348 | packet.data1 = data1 349 | 350 | when VirtDbgAPI::PACKET_TYPE_STATE_CHANGE 351 | data1 = VirtDbgAPI.decode_c_struct('STATE_CHANGE_PACKET', 352 | data, 353 | VirtDbgAPI::HEADER_SIZE) 354 | packet = StateChangePacket.new 355 | packet.data1 = data1 356 | 357 | when VirtDbgAPI::PACKET_TYPE_CONTINUE 358 | data1 = VirtDbgAPI.decode_c_struct('CONTINUE_PACKET', 359 | data, 360 | VirtDbgAPI::HEADER_SIZE) 361 | packet = ContinuePacket.new 362 | packet.data1 = data1 363 | 364 | else 365 | puts "invalid header type" 366 | return 367 | end 368 | 369 | packet.header = header 370 | @lastid = header.Id 371 | # puts packet.to_s 372 | # puts data.hexdump 373 | 374 | @area.LastServerId = header.Id 375 | packet 376 | end 377 | 378 | def breakin 379 | request = BreakinPacket.new 380 | send_packet request 381 | packet = recv_packet 382 | if packet and packet.kind_of? StateChangePacket 383 | @state = :stopped 384 | end 385 | # FIXME need to handle this better 386 | # puts "breakin, got #{packet.inspect}" 387 | packet 388 | end 389 | 390 | def continue 391 | request = ContinuePacket.new(VirtDbgAPI::CONTINUE_STATUS_CONTINUE) 392 | send_packet request 393 | @state = :running 394 | end 395 | 396 | def singlestep 397 | request = ContinuePacket.new(VirtDbgAPI::CONTINUE_STATUS_SINGLE_STEP) 398 | send_packet request 399 | packet = recv_packet 400 | if packet and packet.kind_of? StateChangePacket 401 | @state = :stopped 402 | end 403 | packet 404 | end 405 | 406 | def extract_context(response) 407 | context = {} 408 | context[:rax] = response.data2.rax 409 | context[:rbx] = response.data2.rbx 410 | context[:rcx] = response.data2.rcx 411 | context[:rdx] = response.data2.rdx 412 | context[:rsi] = response.data2.rsi 413 | context[:rdi] = response.data2.rdi 414 | context[:rbp] = response.data2.rbp 415 | context[:rsp] = response.data2.rsp 416 | context[:r8] = response.data2.r8 417 | context[:r9] = response.data2.r9 418 | context[:r10] = response.data2.r10 419 | context[:r11] = response.data2.r11 420 | context[:r12] = response.data2.r12 421 | context[:r13] = response.data2.r13 422 | context[:r14] = response.data2.r14 423 | context[:r15] = response.data2.r15 424 | context[:rip] = response.data2.rip 425 | context[:rflags] = response.data2.rflags 426 | context[:cr0] = response.data2.cr0 427 | context[:cr3] = response.data2.cr3 428 | context[:cr4] = response.data2.cr4 429 | context[:cr8] = response.data2.cr8 430 | context[:dr0] = response.data2.dr0 431 | context[:dr1] = response.data2.dr1 432 | context[:dr2] = response.data2.dr2 433 | context[:dr3] = response.data2.dr3 434 | context[:dr6] = response.data2.dr6 435 | context[:dr7] = response.data2.dr7 436 | context 437 | end 438 | 439 | def fill_context(request, context) 440 | request.data2.rax = context[:rax] if context[:rax] 441 | request.data2.rbx = context[:rbx] if context[:rbx] 442 | request.data2.rcx = context[:rcx] if context[:rcx] 443 | request.data2.rdx = context[:rdx] if context[:rdx] 444 | request.data2.rsi = context[:rsi] if context[:rsi] 445 | request.data2.rdi = context[:rdi] if context[:rdi] 446 | request.data2.rbp = context[:rbp] if context[:rbp] 447 | request.data2.rsp = context[:rsp] if context[:rsp] 448 | request.data2.r8 = context[:r8] if context[:r8] 449 | request.data2.r9 = context[:r9] if context[:r9] 450 | request.data2.r10 = context[:r10] if context[:r10] 451 | request.data2.r11 = context[:r11] if context[:r11] 452 | request.data2.r12 = context[:r12] if context[:r12] 453 | request.data2.r13 = context[:r13] if context[:r13] 454 | request.data2.r14 = context[:r14] if context[:r14] 455 | request.data2.r15 = context[:r15] if context[:r15] 456 | request.data2.rip = context[:rip] if context[:rip] 457 | request.data2.rflags = context[:rflags] if context[:rflags] 458 | request.data2.cr0 = context[:cr0] if context[:cr0] 459 | request.data2.cr3 = context[:cr3] if context[:cr3] 460 | request.data2.cr4 = context[:cr4] if context[:cr4] 461 | request.data2.cr8 = context[:cr8] if context[:cr8] 462 | request.data2.dr0 = context[:dr0] if context[:dr0] 463 | request.data2.dr1 = context[:dr1] if context[:dr1] 464 | request.data2.dr2 = context[:dr2] if context[:dr2] 465 | request.data2.dr3 = context[:dr3] if context[:dr3] 466 | request.data2.dr6 = context[:dr6] if context[:dr6] 467 | request.data2.dr7 = context[:dr7] if context[:dr7] 468 | request 469 | end 470 | 471 | def get_context 472 | return if @state == :running 473 | request = GetContextPacket.new 474 | send_packet request 475 | response = recv_packet_with_type GetContextPacket 476 | if response and response.error == 0 477 | return extract_context(response) 478 | else 479 | return nil 480 | end 481 | end 482 | 483 | def set_context(context) 484 | return if @state == :running 485 | request = SetContextPacket.new 486 | fill_context request, context 487 | send_packet request 488 | response = recv_packet_with_type SetContextPacket 489 | end 490 | 491 | def read_virtual_memory(address, size) 492 | return if @state == :running 493 | request = ReadVirtualMemoryPacket.new(address, size) 494 | send_packet request 495 | response = recv_packet_with_type ReadVirtualMemoryPacket 496 | if response and response.error == 0 497 | return response.data2 498 | else 499 | return nil 500 | end 501 | end 502 | 503 | def write_virtual_memory(address, data) 504 | return if @state == :running 505 | request = WriteVirtualMemoryPacket.new(address, data) 506 | send_packet request 507 | response = recv_packet_with_type WriteVirtualMemoryPacket 508 | end 509 | 510 | end 511 | 512 | end 513 | -------------------------------------------------------------------------------- /src/virtdbg/Makefile: -------------------------------------------------------------------------------- 1 | !INCLUDE $(NTMAKEENV)\makefile.def 2 | 3 | -------------------------------------------------------------------------------- /src/virtdbg/amd64.h: -------------------------------------------------------------------------------- 1 | // This file is part of Virtdbg 2 | // Copyright (C) 2010-2011 Damien AUMAITRE 3 | 4 | // Licence is GPLv3, see LICENCE.txt in the top-level directory 5 | 6 | 7 | #ifndef AMD64_H 8 | #define AMD64_H 9 | 10 | #include 11 | 12 | #define KGDT64_NULL (0 * 16) // NULL descriptor 13 | #define KGDT64_R0_CODE (1 * 16) // kernel mode 64-bit code 14 | #define KGDT64_R0_DATA (1 * 16) + 8 // kernel mode 64-bit data (stack) 15 | #define KGDT64_R3_CMCODE (2 * 16) // user mode 32-bit code 16 | #define KGDT64_R3_DATA (2 * 16) + 8 // user mode 32-bit data 17 | #define KGDT64_R3_CODE (3 * 16) // user mode 64-bit code 18 | #define KGDT64_SYS_TSS (4 * 16) // kernel mode system task state 19 | #define KGDT64_R3_CMTEB (5 * 16) // user mode 32-bit TEB 20 | #define KGDT64_R0_CMCODE (6 * 16) // kernel mode 32-bit code 21 | 22 | #pragma pack (push, 1) 23 | 24 | /* 25 | * Attribute for segment selector. This is a copy of bit 40:47 & 52:55 of the 26 | * segment descriptor. 27 | */ 28 | typedef union 29 | { 30 | USHORT UCHARs; 31 | struct 32 | { 33 | USHORT type:4; /* 0; Bit 40-43 */ 34 | USHORT s:1; /* 4; Bit 44 */ 35 | USHORT dpl:2; /* 5; Bit 45-46 */ 36 | USHORT p:1; /* 7; Bit 47 */ 37 | // gap! 38 | USHORT avl:1; /* 8; Bit 52 */ 39 | USHORT l:1; /* 9; Bit 53 */ 40 | USHORT db:1; /* 10; Bit 54 */ 41 | USHORT g:1; /* 11; Bit 55 */ 42 | USHORT Gap:4; 43 | } fields; 44 | } SEGMENT_ATTRIBUTES; 45 | 46 | typedef struct _TSS64 47 | { 48 | ULONG Reserved0; 49 | PVOID RSP0; 50 | PVOID RSP1; 51 | PVOID RSP2; 52 | ULONG64 Reserved1; 53 | PVOID IST1; 54 | PVOID IST2; 55 | PVOID IST3; 56 | PVOID IST4; 57 | PVOID IST5; 58 | PVOID IST6; 59 | PVOID IST7; 60 | ULONG64 Reserved2; 61 | USHORT Reserved3; 62 | USHORT IOMapBaseAddress; 63 | } TSS64, *PTSS64; 64 | 65 | typedef struct _SEGMENT_SELECTOR 66 | { 67 | USHORT sel; 68 | SEGMENT_ATTRIBUTES attributes; 69 | ULONG32 limit; 70 | ULONG64 base; 71 | } SEGMENT_SELECTOR, *PSEGMENT_SELECTOR; 72 | 73 | typedef struct _SEGMENT_DESCRIPTOR 74 | { 75 | USHORT limit0; 76 | USHORT base0; 77 | UCHAR base1; 78 | UCHAR attr0; 79 | UCHAR limit1attr1; 80 | UCHAR base2; 81 | } SEGMENT_DESCRIPTOR, *PSEGMENT_DESCRIPTOR; 82 | 83 | typedef struct _INTERRUPT_GATE_DESCRIPTOR 84 | { 85 | USHORT TargetOffset1500; 86 | USHORT TargetSelector; 87 | UCHAR InterruptStackTable; 88 | UCHAR Attributes; 89 | USHORT TargetOffset3116; 90 | ULONG32 TargetOffset6332; 91 | ULONG32 Reserved; 92 | } INTERRUPT_GATE_DESCRIPTOR, 93 | *PINTERRUPT_GATE_DESCRIPTOR; 94 | 95 | #pragma pack (pop) 96 | 97 | #define LA_ACCESSED 0x01 98 | #define LA_READABLE 0x02 // for code segments 99 | #define LA_WRITABLE 0x02 // for data segments 100 | #define LA_CONFORMING 0x04 // for code segments 101 | #define LA_EXPANDDOWN 0x04 // for data segments 102 | #define LA_CODE 0x08 103 | #define LA_STANDARD 0x10 104 | #define LA_DPL_0 0x00 105 | #define LA_DPL_1 0x20 106 | #define LA_DPL_2 0x40 107 | #define LA_DPL_3 0x60 108 | #define LA_PRESENT 0x80 109 | 110 | #define LA_LDT64 0x02 111 | #define LA_ATSS64 0x09 112 | #define LA_BTSS64 0x0b 113 | #define LA_CALLGATE64 0x0c 114 | #define LA_INTGATE64 0x0e 115 | #define LA_TRAPGATE64 0x0f 116 | 117 | #define HA_AVAILABLE 0x01 118 | #define HA_LONG 0x02 119 | #define HA_DB 0x04 120 | #define HA_GRANULARITY 0x08 121 | 122 | typedef enum SEGREGS 123 | { 124 | ES = 0, 125 | CS, 126 | SS, 127 | DS, 128 | FS, 129 | GS, 130 | LDTR, 131 | TR 132 | }; 133 | 134 | #define DIVIDE_ERROR_EXCEPTION 0 135 | #define DEBUG_EXCEPTION 1 136 | #define NMI_INTERRUPT 2 137 | #define BREAKPOINT_EXCEPTION 3 138 | #define OVERFLOW_EXCEPTION 4 139 | #define BOUND_EXCEPTION 5 140 | #define INVALID_OPCODE_EXCEPTION 6 141 | #define DEVICE_NOT_AVAILABLE_EXCEPTION 7 142 | #define DOUBLE_FAULT_EXCEPTION 8 143 | #define COPROCESSOR_SEGMENT_OVERRUN 9 144 | #define INVALID_TSS_EXCEPTION 10 145 | #define SEGMENT_NOT_PRESENT 11 146 | #define STACK_FAULT_EXCEPTION 12 147 | #define GENERAL_PROTECTION_EXCEPTION 13 148 | #define PAGE_FAULT_EXCEPTION 14 149 | #define X87_FLOATING_POINT_ERROR 16 150 | #define ALIGNMENT_CHECK_EXCEPTION 17 151 | //#define MACHINE_CHECK_EXCEPTION 18 152 | #define SIMD_FLOATING_POINT_EXCEPTION 19 153 | 154 | #define EXTERNAL_INTERRUPT 0 155 | #define HARDWARE_EXCEPTION 3 156 | #define SOFTWARE_INTERRUPT 4 157 | #define PRIVILEGED_SOFTWARE_EXCEPTION 5 158 | #define SOFTWARE_EXCEPTION 6 159 | #define OTHER_EVENT 7 160 | 161 | #define EFER_LME (1<<8) 162 | #define EFER_LMA (1<<10) 163 | 164 | /* 165 | * Intel CPU flags in CR0 166 | */ 167 | #define X86_CR0_PE 0x00000001 /* Enable Protected Mode (RW) */ 168 | #define X86_CR0_MP 0x00000002 /* Monitor Coprocessor (RW) */ 169 | #define X86_CR0_EM 0x00000004 /* Require FPU Emulation (RO) */ 170 | #define X86_CR0_TS 0x00000008 /* Task Switched (RW) */ 171 | #define X86_CR0_ET 0x00000010 /* Extension type (RO) */ 172 | #define X86_CR0_NE 0x00000020 /* Numeric Error Reporting (RW) */ 173 | #define X86_CR0_WP 0x00010000 /* Supervisor Write Protect (RW) */ 174 | #define X86_CR0_AM 0x00040000 /* Alignment Checking (RW) */ 175 | #define X86_CR0_NW 0x20000000 /* Not Write-Through (RW) */ 176 | #define X86_CR0_CD 0x40000000 /* Cache Disable (RW) */ 177 | #define X86_CR0_PG 0x80000000 /* Paging (RW) */ 178 | 179 | /* 180 | * Intel CPU features in CR4 181 | */ 182 | #define X86_CR4_VME 0x0001 /* enable vm86 extensions */ 183 | #define X86_CR4_PVI 0x0002 /* virtual interrupts flag enable */ 184 | #define X86_CR4_TSD 0x0004 /* disable time stamp at ipl 3 */ 185 | #define X86_CR4_DE 0x0008 /* enable debugging extensions */ 186 | #define X86_CR4_PSE 0x0010 /* enable page size extensions */ 187 | #define X86_CR4_PAE 0x0020 /* enable physical address extensions */ 188 | #define X86_CR4_MCE 0x0040 /* Machine check enable */ 189 | #define X86_CR4_PGE 0x0080 /* enable global pages */ 190 | #define X86_CR4_PCE 0x0100 /* enable performance counters at ipl 3 */ 191 | #define X86_CR4_OSFXSR 0x0200 /* enable fast FPU save and restore */ 192 | #define X86_CR4_OSXMMEXCPT 0x0400 /* enable unmasked SSE exceptions */ 193 | #define X86_CR4_VMXE 0x2000 /* enable VMX */ 194 | 195 | /* 196 | * Intel CPU MSR 197 | */ 198 | 199 | /* MSRs & bits used for VMX enabling */ 200 | 201 | #define MSR_IA32_VMX_BASIC 0x480 202 | #define MSR_IA32_FEATURE_CONTROL 0x03a 203 | #define MSR_IA32_VMX_PINBASED_CTLS 0x481 204 | #define MSR_IA32_VMX_PROCBASED_CTLS 0x482 205 | #define MSR_IA32_VMX_EXIT_CTLS 0x483 206 | #define MSR_IA32_VMX_ENTRY_CTLS 0x484 207 | 208 | #define MSR_IA32_SYSENTER_CS 0x174 209 | #define MSR_IA32_SYSENTER_ESP 0x175 210 | #define MSR_IA32_SYSENTER_EIP 0x176 211 | #define MSR_IA32_DEBUGCTL 0x1d9 212 | 213 | /* x86-64 MSR */ 214 | 215 | #define MSR_EFER 0xc0000080 /* extended feature register */ 216 | #define MSR_STAR 0xc0000081 /* legacy mode SYSCALL target */ 217 | #define MSR_LSTAR 0xc0000082 /* long mode SYSCALL target */ 218 | #define MSR_CSTAR 0xc0000083 /* compatibility mode SYSCALL target */ 219 | #define MSR_SYSCALL_MASK 0xc0000084 /* EFLAGS mask for syscall */ 220 | #define MSR_FS_BASE 0xc0000100 /* 64bit FS base */ 221 | #define MSR_GS_BASE 0xc0000101 /* 64bit GS base */ 222 | #define MSR_SHADOW_GS_BASE 0xc0000102 /* SwapGS GS shadow */ 223 | 224 | #define CR0 0 225 | #define CR3 3 226 | #define CR4 4 227 | #define CR8 8 228 | 229 | #define RAX 0 230 | #define RCX 1 231 | #define RDX 2 232 | #define RBX 3 233 | #define RSP 4 234 | #define RBP 5 235 | #define RSI 6 236 | #define RDI 7 237 | #define R8 8 238 | #define R9 9 239 | #define R10 10 240 | #define R11 11 241 | #define R12 12 242 | #define R13 13 243 | #define R14 14 244 | #define R15 15 245 | 246 | // 247 | // Used by the cpuid instruction when eax=1 248 | // 249 | 250 | typedef struct _VMX_FEATURES { 251 | unsigned SSE3 :1; // SSE3 Extensions 252 | unsigned RES1 :2; 253 | unsigned MONITOR :1; // MONITOR/WAIT 254 | unsigned DS_CPL :1; // CPL qualified Debug Store 255 | unsigned VMX :1; // Virtual Machine Technology 256 | unsigned RES2 :1; 257 | unsigned EST :1; // Enhanced Intel© Speedstep Technology 258 | unsigned TM2 :1; // Thermal monitor 2 259 | unsigned SSSE3 :1; // SSSE3 extensions 260 | unsigned CID :1; // L1 context ID 261 | unsigned RES3 :2; 262 | unsigned CX16 :1; // CMPXCHG16B 263 | unsigned xTPR :1; // Update control 264 | unsigned PDCM :1; // Performance/Debug capability MSR 265 | unsigned RES4 :2; 266 | unsigned DCA :1; 267 | unsigned RES5 :13; 268 | } VMX_FEATURES; 269 | 270 | typedef struct _IA32_FEATURE_CONTROL_MSR { 271 | unsigned Lock :1; // Bit 0 is the lock bit - cannot be 272 | // modified once lock is set, controled by BIOS 273 | unsigned VmxonInSmx :1; 274 | unsigned VmxonOutSmx :1; 275 | unsigned Reserved2 :29; 276 | unsigned Reserved3 :32; 277 | } IA32_FEATURE_CONTROL_MSR; 278 | 279 | typedef struct _CR4_REG { 280 | unsigned VME :1; // Virtual Mode Extensions 281 | unsigned PVI :1; // Protected-Mode Virtual Interrupts 282 | unsigned TSD :1; // Time Stamp Disable 283 | unsigned DE :1; // Debugging Extensions 284 | unsigned PSE :1; // Page Size Extensions 285 | unsigned PAE :1; // Physical Address Extension 286 | unsigned MCE :1; // Machine-Check Enable 287 | unsigned PGE :1; // Page Global Enable 288 | unsigned PCE :1; // Performance-Monitoring Counter Enable 289 | unsigned OSFXSR :1; // OS Support for FXSAVE/FXRSTOR 290 | unsigned OSXMMEXCPT :1; // OS Support for Unmasked SIMD Floating-Point Exceptions 291 | unsigned Reserved1 :2; // 292 | unsigned VMXE :1; // Virtual Machine Extensions Enabled 293 | unsigned Reserved2 :18; // 294 | } CR4_REG, *PCR4_REG; 295 | 296 | 297 | typedef struct _RFLAGS { 298 | unsigned CF:1; 299 | unsigned Reserved1:1; 300 | unsigned PF:1; 301 | unsigned Reserved2:1; 302 | unsigned AF:1; 303 | unsigned Reserved3:1; 304 | unsigned ZF:1; 305 | unsigned SF:1; 306 | unsigned TF:1; 307 | unsigned IF:1; 308 | unsigned DF:1; 309 | unsigned OF:1; 310 | unsigned IOPL:2; 311 | unsigned NT:1; 312 | unsigned Reserved4:1; 313 | unsigned RF:1; 314 | unsigned VM:1; 315 | unsigned AC:1; 316 | unsigned VIF:1; 317 | unsigned VIP:1; 318 | unsigned ID:1; 319 | unsigned Reserved5:10; 320 | } RFLAGS, *PRFLAGS; 321 | 322 | #define TF 0x100 323 | 324 | typedef union _DR6 { 325 | ULONG Value; 326 | struct { 327 | unsigned B0:1; 328 | unsigned B1:1; 329 | unsigned B2:1; 330 | unsigned B3:1; 331 | unsigned Reserved1:10; 332 | unsigned BD:1; 333 | unsigned BS:1; 334 | unsigned BT:1; 335 | unsigned Reserved2:16; 336 | }; 337 | } DR6, *PDR6; 338 | 339 | typedef union _DR7 { 340 | ULONG Value; 341 | struct { 342 | unsigned L0:1; 343 | unsigned G0:1; 344 | unsigned L1:1; 345 | unsigned G1:1; 346 | unsigned L2:1; 347 | unsigned G2:1; 348 | unsigned L3:1; 349 | unsigned G3:1; 350 | unsigned LE:1; 351 | unsigned GE:1; 352 | unsigned Reserved1:3; 353 | unsigned GD:1; 354 | unsigned Reserved2:2; 355 | unsigned RW0:2; 356 | unsigned LEN0:2; 357 | unsigned RW1:2; 358 | unsigned LEN1:2; 359 | unsigned RW2:2; 360 | unsigned LEN2:2; 361 | unsigned RW3:2; 362 | unsigned LEN3:2; 363 | }; 364 | } DR7, *PDR7; 365 | 366 | typedef union _IA32_DEBUGCTL_MSR 367 | { 368 | ULONG Value; 369 | struct { 370 | unsigned LBR:1; 371 | unsigned BTF:1; 372 | unsigned Reserved1:4; 373 | unsigned TR:1; 374 | unsigned BTS:1; 375 | unsigned BTINT:1; 376 | unsigned BTS_OFF_OS:1; 377 | unsigned BTS_OFF_USR:1; 378 | unsigned FREEZE_LBRS_ON_PMI:1; 379 | unsigned FREEZE_PERFMON_ON_PMI:1; 380 | unsigned Reserved2:1; 381 | unsigned FREEZE_WHILE_SMM_EN:1; 382 | }; 383 | } IA32_DEBUGCTL_MSR, *PIA32_DEBUGCTL_MSR; 384 | 385 | typedef struct _MSR { 386 | ULONG Lo; 387 | ULONG Hi; 388 | } MSR, *PMSR; 389 | 390 | typedef struct _VMX_BASIC_MSR { 391 | unsigned RevId:32; 392 | unsigned szVmxOnRegion:12; 393 | unsigned ClearBit:1; 394 | unsigned Reserved:3; 395 | unsigned PhysicalWidth:1; 396 | unsigned DualMonitor:1; 397 | unsigned MemoryType:4; 398 | unsigned VmExitInformation:1; 399 | unsigned Reserved2:9; 400 | } VMX_BASIC_MSR, *PVMX_BASIC_MSR; 401 | 402 | typedef struct _GUEST_REGS 403 | { 404 | ULONG64 rax; 405 | ULONG64 rcx; 406 | ULONG64 rdx; 407 | ULONG64 rbx; 408 | ULONG64 rsp; 409 | ULONG64 rbp; 410 | ULONG64 rsi; 411 | ULONG64 rdi; 412 | ULONG64 r8; 413 | ULONG64 r9; 414 | ULONG64 r10; 415 | ULONG64 r11; 416 | ULONG64 r12; 417 | ULONG64 r13; 418 | ULONG64 r14; 419 | ULONG64 r15; 420 | } GUEST_REGS, *PGUEST_REGS; 421 | 422 | USHORT _Cs(); 423 | USHORT _Ds(); 424 | USHORT _Es(); 425 | USHORT _Ss(); 426 | USHORT _Fs(); 427 | USHORT _Gs(); 428 | ULONG64 _Cr0(); 429 | ULONG64 _Cr2(); 430 | VOID _SetCr2(ULONG64 NewCr2); 431 | ULONG64 _Cr3(); 432 | ULONG64 _Cr4(); 433 | VOID _SetCr4(ULONG32 mask); 434 | 435 | ULONG64 _Cr8(); 436 | ULONG64 _Rflags(); 437 | ULONG64 _Rsp(); 438 | 439 | ULONG64 _IdtBase(); 440 | USHORT _IdtLimit(); 441 | ULONG64 _GdtBase(); 442 | USHORT _GdtLimit(); 443 | USHORT _Ldtr(); 444 | 445 | USHORT _TrSelector(); 446 | 447 | ULONG64 _Rbx(); 448 | ULONG64 _Rax(); 449 | 450 | ULONG64 _TSC(); 451 | 452 | ULONG64 _Dr0(); 453 | ULONG64 _Dr1(); 454 | ULONG64 _Dr2(); 455 | ULONG64 _Dr3(); 456 | ULONG64 _Dr6(); 457 | ULONG64 _SetDr0(); 458 | ULONG64 _SetDr1(); 459 | ULONG64 _SetDr2(); 460 | ULONG64 _SetDr3(); 461 | 462 | ULONG64 _SetCr3(PVOID NewCr3); 463 | ULONG64 _SetCr8(ULONG64 NewCr8); 464 | 465 | VOID _CpuId(ULONG32 fn, OUT PULONG32 ret_eax, OUT PULONG32 ret_ebx, OUT 466 | PULONG32 ret_ecx, OUT PULONG32 ret_edx); 467 | 468 | ULONG64 _ReadMsr(ULONG32 reg); 469 | VOID _WriteMsr(ULONG32 reg, ULONG64 MsrValue); 470 | 471 | VOID _VmxOn(PHYSICAL_ADDRESS PA); 472 | VOID _VmxOff(ULONG64 Rip, ULONG64 Rsp); 473 | ULONG64 _ReadVMCS(ULONG32 Encoding); 474 | VOID _WriteVMCS(ULONG32 Encoding, ULONG64 Value); 475 | VOID _VmPtrLd(PHYSICAL_ADDRESS PA); 476 | VOID _VmClear(PHYSICAL_ADDRESS PA); 477 | ULONG _VmLaunch(); 478 | VOID _VmResume(); 479 | 480 | ULONG32 _VmFailValid(); 481 | ULONG32 _VmFailInvalid(); 482 | 483 | VOID _GuestEntryPoint(); 484 | VOID _ExitHandler(); 485 | NTSTATUS _StartVirtualization(); 486 | 487 | VOID _StopVirtualization(); 488 | VOID _GuestExit(); 489 | 490 | VOID _Int3(); 491 | VOID _Invd(); 492 | 493 | VOID _InvalidatePage(ULONG64 Page); 494 | VOID _SetInterrupts(); 495 | VOID _ClearInterrupts(); 496 | 497 | VOID _InitSpinLock(PULONG32 Lock); 498 | VOID _AcquireSpinLock(PULONG32 Lock); 499 | VOID _ReleaseSpinLock(PULONG32 Lock); 500 | 501 | 502 | #endif 503 | -------------------------------------------------------------------------------- /src/virtdbg/debug.h: -------------------------------------------------------------------------------- 1 | // This file is part of Virtdbg 2 | // Copyright (C) 2010-2011 Damien AUMAITRE 3 | 4 | // Licence is GPLv3, see LICENCE.txt in the top-level directory 5 | 6 | 7 | #ifndef _VIRTDBG_DEBUG_H 8 | #define _VIRTDBG_DEBUG_H 9 | 10 | #include 11 | #include "amd64.h" 12 | #include "vmx.h" 13 | #include "mem.h" 14 | #include "protocol.h" 15 | 16 | NTSTATUS InitDebugLayer(); 17 | 18 | static BOOLEAN HandleVmInstruction(PVIRT_CPU pCpu, PGUEST_REGS pGuestRegs); 19 | static BOOLEAN HandleUnimplemented(PVIRT_CPU pCpu, PGUEST_REGS pGuestRegs, ULONG64 ExitCode); 20 | static BOOLEAN HandleCpuid(PVIRT_CPU pCpu, PGUEST_REGS pGuestRegs); 21 | static BOOLEAN HandleMsrRead(PVIRT_CPU pCpu, PGUEST_REGS pGuestRegs); 22 | static BOOLEAN HandleMsrWrite(PVIRT_CPU pCpu, PGUEST_REGS pGuestRegs); 23 | static BOOLEAN HandleDrAccess(PVIRT_CPU pCpu, PGUEST_REGS pGuestRegs); 24 | static BOOLEAN HandleCrAccess(PVIRT_CPU pCpu, PGUEST_REGS pGuestRegs); 25 | static BOOLEAN HandleException(PVIRT_CPU pCpu, PGUEST_REGS pGuestRegs); 26 | static BOOLEAN HandleNmi(PVIRT_CPU pCpu, PGUEST_REGS pGuestRegs); 27 | static BOOLEAN HandleInvd(PVIRT_CPU pCpu, PGUEST_REGS pGuestRegs); 28 | 29 | VOID HandleVmExit(PVIRT_CPU pCpu, PGUEST_REGS pGuestRegs); 30 | 31 | static VOID EnableTF(); 32 | static VOID DisableTF(); 33 | 34 | static VOID ReportException(PVIRT_CPU pCpu, PGUEST_REGS pGuestRegs, ULONG Exception, ULONG64 Address); 35 | static BOOLEAN EnterDebugger(PVIRT_CPU pCpu, PGUEST_REGS pGuestRegs, ULONG64 Cr3); 36 | static VOID FreezeExecution(PVIRT_CPU pCpu); 37 | static VOID ResumeCpus(ULONG32 RunningProcessor); 38 | static VOID FreezeCpus(ULONG32 RunningProcessor); 39 | 40 | static BOOLEAN HandleClientRequest(PVIRT_CPU pCpu, PGUEST_REGS pGuestRegs, ULONG64 Cr3); 41 | 42 | static BOOLEAN HandleContinuePacket(PVIRT_CPU pCpu, PGUEST_REGS pGuestRegs, PVOID pPacket); 43 | 44 | static BOOLEAN HandleBreakinPacket(PVIRT_CPU pCpu, PGUEST_REGS pGuestRegs, PVOID pPacket, ULONG64 Cr3); 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /src/virtdbg/driver.c: -------------------------------------------------------------------------------- 1 | // This file is part of Virtdbg 2 | // Copyright (C) 2010-2011 Damien AUMAITRE 3 | 4 | // Licence is GPLv3, see LICENCE.txt in the top-level directory 5 | 6 | 7 | #include "driver.h" 8 | 9 | NTSTATUS DriverUnload(PDRIVER_OBJECT DriverObject) 10 | { 11 | CCHAR i; 12 | KIRQL OldIrql; 13 | KAFFINITY OldAffinity; 14 | 15 | for (i=0; iDriverUnload = DriverUnload;*/ 33 | 34 | Status = PsCreateSystemThread(&hThread, 35 | THREAD_ALL_ACCESS, 36 | NULL, 37 | NULL, 38 | NULL, 39 | VirtDbgStart, NULL); 40 | if (!NT_SUCCESS(Status)) 41 | { 42 | return Status; 43 | } 44 | 45 | return STATUS_SUCCESS; 46 | } 47 | 48 | 49 | -------------------------------------------------------------------------------- /src/virtdbg/driver.h: -------------------------------------------------------------------------------- 1 | // This file is part of Virtdbg 2 | // Copyright (C) 2010-2011 Damien AUMAITRE 3 | 4 | // Licence is GPLv3, see LICENCE.txt in the top-level directory 5 | 6 | 7 | #ifndef _VIRTDBG_DRIVER_H 8 | #define _VIRTDBG_DRIVER_H 9 | 10 | #include 11 | #include "virtdbg.h" 12 | 13 | #endif 14 | 15 | -------------------------------------------------------------------------------- /src/virtdbg/log.c: -------------------------------------------------------------------------------- 1 | // This file is part of Virtdbg 2 | // Copyright (C) 2010-2011 Damien AUMAITRE 3 | 4 | // Licence is GPLv3, see LICENCE.txt in the top-level directory 5 | 6 | 7 | #include "log.h" 8 | 9 | PVOID g_LogBuffer = NULL; 10 | static LONG g_LogIndex = 0; 11 | static PKSPIN_LOCK g_LogLock; 12 | 13 | PVOID InitLog() 14 | { 15 | g_LogBuffer = AllocateMemory(LOGBUFFER_SIZE); 16 | 17 | if (g_LogBuffer == NULL) 18 | return NULL; 19 | 20 | g_LogLock = AllocateMemory(sizeof(KSPIN_LOCK)); 21 | 22 | if (g_LogLock == NULL) 23 | return NULL; 24 | 25 | KeInitializeSpinLock(g_LogLock); 26 | 27 | return g_LogBuffer; 28 | } 29 | 30 | static BOOLEAN InsertLogEntry(char *buffer, unsigned short size) 31 | { 32 | if (g_LogBuffer == NULL) 33 | return FALSE; 34 | 35 | if (g_LogIndex+size > LOGBUFFER_SIZE) 36 | { 37 | RtlZeroMemory(g_LogBuffer, LOGBUFFER_SIZE); 38 | g_LogIndex = 0; 39 | } 40 | 41 | RtlCopyMemory((PUCHAR)g_LogBuffer+g_LogIndex, buffer, size); 42 | InterlockedExchangeAdd(&g_LogIndex, size); 43 | return TRUE; 44 | } 45 | 46 | VOID Log(char *format, ...) 47 | { 48 | KIRQL CurrentIrql; 49 | 50 | unsigned short size; 51 | va_list args; 52 | UCHAR buffer[1024] = {0}; 53 | 54 | va_start(args, format); 55 | 56 | CurrentIrql = KeGetCurrentIrql(); 57 | if (CurrentIrql < DISPATCH_LEVEL) 58 | { 59 | KeRaiseIrqlToDpcLevel(); 60 | } 61 | 62 | KeAcquireSpinLockAtDpcLevel(g_LogLock); 63 | 64 | /* RtlZeroMemory(&buffer, sizeof(buffer));*/ 65 | /* vsnprintf((PUCHAR)&buffer, sizeof(buffer), "%d:", g_LogIndex);*/ 66 | /* buffer[1023] = '\0';*/ 67 | /* size = strlen(buffer);*/ 68 | 69 | /* InsertLogEntry(buffer, size);*/ 70 | /* */ 71 | 72 | RtlZeroMemory(&buffer, sizeof(buffer)); 73 | vsnprintf((PUCHAR)&buffer, sizeof(buffer), (PUCHAR)format, args); 74 | buffer[1023] = '\0'; 75 | size = strlen(buffer); 76 | 77 | InsertLogEntry(buffer, size); 78 | 79 | KeReleaseSpinLockFromDpcLevel(g_LogLock); 80 | 81 | if (CurrentIrql < DISPATCH_LEVEL) 82 | { 83 | KeLowerIrql(CurrentIrql); 84 | } 85 | } 86 | 87 | 88 | -------------------------------------------------------------------------------- /src/virtdbg/log.h: -------------------------------------------------------------------------------- 1 | // This file is part of Virtdbg 2 | // Copyright (C) 2010-2011 Damien AUMAITRE 3 | 4 | // Licence is GPLv3, see LICENCE.txt in the top-level directory 5 | 6 | 7 | #ifndef VIRTDBG_LOG_H 8 | #define VIRTDBG_LOG_H 9 | 10 | #include 11 | #include "snprintf.h" 12 | #include "mem.h" 13 | #include 14 | 15 | #define LOGBUFFER_SIZE 0x1000 16 | 17 | 18 | PVOID InitLog(); 19 | VOID Log(char *format, ...); 20 | 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /src/virtdbg/mem.c: -------------------------------------------------------------------------------- 1 | // This file is part of Virtdbg 2 | // Copyright (C) 2010-2011 Damien AUMAITRE 3 | 4 | // Licence is GPLv3, see LICENCE.txt in the top-level directory 5 | 6 | 7 | #include "mem.h" 8 | 9 | PVOID AllocateMemory(ULONG32 Size) 10 | { 11 | PVOID pMem = NULL; 12 | pMem = ExAllocatePoolWithTag(NonPagedPool, Size, VIRTDBG_POOLTAG); 13 | if (pMem == NULL) 14 | return NULL; 15 | 16 | RtlZeroMemory(pMem, Size); 17 | return pMem; 18 | } 19 | 20 | VOID UnAllocateMemory(PVOID pMem) 21 | { 22 | ExFreePoolWithTag(pMem, VIRTDBG_POOLTAG); 23 | } 24 | 25 | PVOID AllocateContiguousMemory(ULONG size) 26 | { 27 | PVOID Address; 28 | PHYSICAL_ADDRESS l1, l2, l3; 29 | 30 | l1.QuadPart = 0; 31 | l2.QuadPart = -1; 32 | l3.QuadPart = 0x200000; 33 | 34 | Address = MmAllocateContiguousMemorySpecifyCache(size, l1, l2, l3, MmCached); 35 | 36 | if (Address == NULL) 37 | { 38 | return NULL; 39 | } 40 | 41 | RtlZeroMemory(Address, size); 42 | return Address; 43 | } 44 | 45 | NTSTATUS IsPagePresent(ULONG64 PageVA) 46 | { 47 | ULONG64 Pml4e, Pdpe, Pde, Pte; 48 | 49 | Pml4e = *(PULONG64)(((PageVA >> 36) & 0xff8) + PML4_BASE); 50 | 51 | if (!(Pml4e & P_PRESENT)) 52 | return STATUS_NO_MEMORY; 53 | 54 | Pdpe = *(PULONG64)(((PageVA >> 27) & 0x1ffff8) + PDP_BASE); 55 | 56 | if (!(Pdpe & P_PRESENT)) 57 | return STATUS_NO_MEMORY; 58 | 59 | Pde = *(PULONG64)(((PageVA >> 18) & 0x3ffffff8) + PD_BASE); 60 | 61 | if (!(Pde & P_PRESENT)) 62 | return STATUS_NO_MEMORY; 63 | 64 | if ((Pde & P_LARGE) == P_LARGE) 65 | return STATUS_SUCCESS; 66 | 67 | Pte = *(PULONG64)(((PageVA >> 9) & 0x7ffffffff8) + PT_BASE); 68 | 69 | if (!(Pte & P_PRESENT)) 70 | return STATUS_NO_MEMORY; 71 | 72 | return STATUS_SUCCESS; 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/virtdbg/mem.h: -------------------------------------------------------------------------------- 1 | // This file is part of Virtdbg 2 | // Copyright (C) 2010-2011 Damien AUMAITRE 3 | 4 | // Licence is GPLv3, see LICENCE.txt in the top-level directory 5 | 6 | 7 | #ifndef _MEM_H 8 | #define _MEM_H 9 | 10 | #include 11 | 12 | #define P_PRESENT 0x01 13 | #define P_WRITABLE 0x02 14 | #define P_USERMODE 0x04 15 | #define P_WRITETHROUGH 0x08 16 | #define P_CACHE_DISABLED 0x10 17 | #define P_ACCESSED 0x20 18 | #define P_DIRTY 0x40 19 | #define P_LARGE 0x80 20 | #define P_GLOBAL 0x100 21 | 22 | #define PML4_BASE 0xfffff6fb7dbed000ULL 23 | #define PDP_BASE 0xfffff6fb7da00000ULL 24 | #define PD_BASE 0xfffff6fb40000000ULL 25 | #define PT_BASE 0xfffff68000000000ULL 26 | 27 | #define VIRTDBG_POOLTAG 0xbad0bad0 28 | 29 | PVOID AllocateMemory(ULONG32 Size); 30 | VOID UnAllocateMemory(PVOID pMem); 31 | PVOID AllocateContiguousMemory(ULONG size); 32 | NTSTATUS IsPagePresent(ULONG64 PageVA); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/virtdbg/misc.h: -------------------------------------------------------------------------------- 1 | // This file is part of Virtdbg 2 | // Copyright (C) 2010-2011 Damien AUMAITRE 3 | 4 | // Licence is GPLv3, see LICENCE.txt in the top-level directory 5 | 6 | 7 | #ifndef _VIRTDBG_MISC_H 8 | #define _VIRTDBG_MISC_H 9 | 10 | #include 11 | #include "log.h" 12 | 13 | //#define DbgLog(_args_) { DbgPrint("virtdbg[#%d][IRQL=0x%x](%s): ", KeGetCurrentProcessorNumber(), KeGetCurrentIrql(), __FUNCTION__); DbgPrint _args_; } 14 | #define DbgLog(_args_) { Log("vmx[#%d][IRQL=0x%x](%s): ", KeGetCurrentProcessorNumber(), KeGetCurrentIrql(), __FUNCTION__); Log _args_; } 15 | 16 | 17 | #endif 18 | 19 | -------------------------------------------------------------------------------- /src/virtdbg/protocol.c: -------------------------------------------------------------------------------- 1 | // This file is part of Virtdbg 2 | // Copyright (C) 2010-2011 Damien AUMAITRE 3 | 4 | // Licence is GPLv3, see LICENCE.txt in the top-level directory 5 | 6 | 7 | #include "protocol.h" 8 | 9 | static LONG g_Id = 0; 10 | static ULONG32 g_LastId = 0; 11 | static ULONG32 g_ClientId = 0; 12 | static PVOID g_SendArea = NULL; 13 | static PVOID g_RecvArea = NULL; 14 | 15 | extern PVIRTDBG_CONTROL_AREA g_ControlArea; 16 | 17 | NTSTATUS InitProtocolLayer(PVOID SendArea, PVOID RecvArea) 18 | { 19 | g_SendArea = SendArea; 20 | g_RecvArea = RecvArea; 21 | g_Id = INITIAL_ID; 22 | return STATUS_SUCCESS; 23 | } 24 | 25 | 26 | static ULONG32 CalcChecksum(PVOID Src, ULONG32 Size) 27 | { 28 | ULONG32 Checksum; 29 | ULONG32 i; 30 | 31 | Checksum = 0; 32 | for (i=0;iId = g_Id; 45 | pHeader->ClientId = g_ClientId; 46 | pHeader->Checksum = CalcChecksum((PUCHAR)pPacket+sizeof(PACKET_HEADER), 47 | pHeader->Size); 48 | } 49 | 50 | 51 | BOOLEAN SendPacket(PVOID pPacket, ULONG32 MaxRetries) 52 | { 53 | PPACKET_HEADER pHeader; 54 | ULONG32 Size, retries; 55 | 56 | retries = 0; 57 | pHeader = (PPACKET_HEADER)pPacket; 58 | 59 | FixUpPacket(pPacket); 60 | Size = pHeader->Size+sizeof(PACKET_HEADER); 61 | 62 | if (g_SendArea == NULL) 63 | { 64 | DbgLog(("not initialized ?\n")); 65 | return FALSE; 66 | } 67 | 68 | if (Size > MAX_PACKET_SIZE) 69 | { 70 | DbgLog(("packet too big\n")); 71 | return FALSE; 72 | } 73 | 74 | RtlCopyMemory(g_SendArea, pPacket, Size); 75 | DestroyPacket(pPacket); 76 | 77 | while (retries < MaxRetries) 78 | { 79 | retries++; 80 | if (g_ControlArea->LastServerId == pHeader->Id) 81 | { 82 | InterlockedIncrement(&g_Id); 83 | DbgLog(("packet successfully sent\n")); 84 | return TRUE; 85 | } 86 | } 87 | DbgLog(("no ack after %d retries\n", retries)); 88 | return FALSE; 89 | } 90 | 91 | VOID CheckNewClientId() 92 | { 93 | if (g_ControlArea == NULL) 94 | return; 95 | 96 | g_ControlArea->ServerId = g_ControlArea->ClientId; 97 | if (g_ControlArea->ClientId != g_ClientId) 98 | { 99 | DbgLog(("new client : 0x%x\n", g_ControlArea->ClientId)); 100 | g_ClientId = g_ControlArea->ClientId; 101 | g_Id = INITIAL_ID; 102 | g_LastId = 0; 103 | DbgLog(("send @ 0x%llx (0x%llx) recv @ 0x%llx (0x%llx)\n", g_SendArea, g_ControlArea->RecvArea, g_RecvArea, g_ControlArea->SendArea)); 104 | DbgLog(("sizeof(MANIPULATE_STATE_PACKET)=0x%x\n", 105 | sizeof(MANIPULATE_STATE_PACKET))); 106 | DbgLog(("sizeof(PACKET_HEADER)=0x%x\n", 107 | sizeof(PACKET_HEADER))); 108 | 109 | } 110 | 111 | } 112 | 113 | PVOID ReceivePacket() 114 | { 115 | PVOID pPacket; 116 | PPACKET_HEADER pHeader; 117 | ULONG32 Size, Checksum; 118 | 119 | CheckNewClientId(); 120 | 121 | if (g_RecvArea == NULL) 122 | { 123 | DbgLog(("not initialized ?\n")); 124 | return NULL; 125 | } 126 | 127 | pHeader = (PPACKET_HEADER)(g_RecvArea); 128 | if (pHeader->Magic != PACKET_MAGIC) 129 | return NULL; 130 | 131 | if (pHeader->Size > MAX_PACKET_SIZE) 132 | return NULL; 133 | 134 | if (pHeader->Id <= g_LastId) 135 | return NULL; 136 | 137 | Size = sizeof(PACKET_HEADER) + pHeader->Size; 138 | pPacket = AllocateMemory(Size); 139 | if (pPacket == NULL) 140 | { 141 | return NULL; 142 | } 143 | 144 | RtlCopyMemory(pPacket, g_RecvArea, Size); 145 | 146 | if (pHeader->Size > 0) 147 | { 148 | Checksum = CalcChecksum((PUCHAR)pPacket+sizeof(PACKET_HEADER), 149 | pHeader->Size); 150 | if (Checksum != pHeader->Checksum) 151 | { 152 | UnAllocateMemory(pPacket); 153 | return NULL; 154 | } 155 | } 156 | 157 | g_LastId = pHeader->Id; 158 | g_ControlArea->LastClientId = g_LastId; 159 | DbgLog(("Received packet (id=0x%x)\n", g_LastId)); 160 | return pPacket; 161 | 162 | } 163 | 164 | 165 | static PVOID CreateBreakinPacket() 166 | { 167 | PVOID pPacket; 168 | PPACKET_HEADER pHeader; 169 | ULONG32 Size; 170 | 171 | Size = sizeof(PACKET_HEADER)+sizeof(BREAKIN_PACKET); 172 | 173 | pPacket = AllocateMemory(Size); 174 | if (pPacket == NULL) 175 | return NULL; 176 | 177 | pHeader = (PPACKET_HEADER)pPacket; 178 | pHeader->Magic = PACKET_MAGIC; 179 | pHeader->Type = PACKET_TYPE_BREAKIN; 180 | pHeader->Size = sizeof(BREAKIN_PACKET); 181 | 182 | return pPacket; 183 | 184 | } 185 | 186 | PVOID CreateManipulateStatePacket(ULONG32 ApiNumber, ULONG32 Data2Size) 187 | { 188 | PVOID pPacket; 189 | PPACKET_HEADER pHeader; 190 | PMANIPULATE_STATE_PACKET pData1; 191 | ULONG32 Size; 192 | 193 | Size = sizeof(PACKET_HEADER)+sizeof(MANIPULATE_STATE_PACKET)+Data2Size; 194 | 195 | pPacket = AllocateMemory(Size); 196 | if (pPacket == NULL) 197 | return NULL; 198 | 199 | pHeader = (PPACKET_HEADER)pPacket; 200 | pHeader->Magic = PACKET_MAGIC; 201 | pHeader->Type = PACKET_TYPE_MANIPULATE_STATE; 202 | pHeader->Size = sizeof(MANIPULATE_STATE_PACKET)+Data2Size; 203 | 204 | pData1 = (PMANIPULATE_STATE_PACKET)((PUCHAR)pPacket+sizeof(PACKET_HEADER)); 205 | pData1->ApiNumber = ApiNumber; 206 | return pPacket; 207 | } 208 | 209 | PVOID CreateStateChangePacket(ULONG32 Exception, ULONG64 Address) 210 | { 211 | PVOID pPacket; 212 | PPACKET_HEADER pHeader; 213 | 214 | PSTATE_CHANGE_PACKET pData1; 215 | ULONG32 Size; 216 | 217 | Size = sizeof(PACKET_HEADER)+sizeof(STATE_CHANGE_PACKET); 218 | pPacket = AllocateMemory(Size); 219 | if (pPacket == NULL) 220 | return NULL; 221 | 222 | pHeader = (PPACKET_HEADER)pPacket; 223 | pHeader->Magic = PACKET_MAGIC; 224 | pHeader->Type = PACKET_TYPE_STATE_CHANGE; 225 | pHeader->Size = sizeof(STATE_CHANGE_PACKET); 226 | 227 | pData1 = (PSTATE_CHANGE_PACKET)((PUCHAR)pPacket+sizeof(PACKET_HEADER)); 228 | pData1->Exception = Exception; 229 | pData1->Address = Address; 230 | return pPacket; 231 | } 232 | 233 | 234 | VOID DestroyPacket(PVOID pPacket) 235 | { 236 | UnAllocateMemory(pPacket); 237 | } 238 | 239 | 240 | -------------------------------------------------------------------------------- /src/virtdbg/protocol.h: -------------------------------------------------------------------------------- 1 | // This file is part of Virtdbg 2 | // Copyright (C) 2010-2011 Damien AUMAITRE 3 | 4 | // Licence is GPLv3, see LICENCE.txt in the top-level directory 5 | 6 | 7 | #ifndef _VIRTDBG_PROTOCOL_H 8 | #define _VIRTDBG_PROTOCOL_H 9 | 10 | #include 11 | #include "misc.h" 12 | #include "mem.h" 13 | 14 | typedef struct _VIRTDBG_CONTROL_AREA 15 | { 16 | ULONG32 Magic1; 17 | ULONG32 Magic2; 18 | PHYSICAL_ADDRESS SendArea; 19 | PHYSICAL_ADDRESS RecvArea; 20 | PVOID KernelBase; 21 | PVOID DebuggerData; 22 | PHYSICAL_ADDRESS LogBuffer; 23 | ULONG32 ClientId; 24 | ULONG32 ServerId; 25 | ULONG32 LastClientId; 26 | ULONG32 LastServerId; 27 | LONG State; 28 | } VIRTDBG_CONTROL_AREA, *PVIRTDBG_CONTROL_AREA; 29 | 30 | #define CONTROL_AREA_SIZE 0x1000 31 | #define CONTROL_AREA_MAGIC1 0xbabebabe 32 | #define CONTROL_AREA_MAGIC2 0xcafecafe 33 | 34 | typedef struct _PACKET_HEADER { 35 | ULONG32 Magic; 36 | ULONG32 Type; 37 | ULONG32 Size; 38 | ULONG32 Id; 39 | ULONG32 ClientId; 40 | ULONG32 Checksum; 41 | } PACKET_HEADER, *PPACKET_HEADER; 42 | 43 | typedef struct _BREAKIN_PACKET { 44 | ULONG64 Cr3; 45 | } BREAKIN_PACKET, *PBREAKIN_PACKET; 46 | 47 | #define CONTINUE_STATUS_SINGLE_STEP 0x1 48 | #define CONTINUE_STATUS_UNLOAD 0x2 49 | #define CONTINUE_STATUS_CONTINUE 0x3 50 | 51 | typedef struct _CONTINUE_PACKET { 52 | ULONG32 Status; 53 | } CONTINUE_PACKET, *PCONTINUE_PACKET; 54 | 55 | typedef struct _SOFTWARE_BREAKPOINT_PACKET { 56 | ULONG64 Address; 57 | } SOFTWARE_BREAKPOINT_PACKET, *PSOFTWARE_BREAKPOINT_PACKET; 58 | 59 | typedef struct _HARDWARE_BREAKPOINT_PACKET { 60 | ULONG64 Address; 61 | } HARDWARE_BREAKPOINT_PACKET, *PHARDWARE_BREAKPOINT_PACKET; 62 | 63 | typedef struct _MEMORY_BREAKPOINT_PACKET { 64 | ULONG64 Address; 65 | } MEMORY_BREAKPOINT_PACKET, *PMEMORY_BREAKPOINT_PACKET; 66 | 67 | typedef struct _STATE_CHANGE_PACKET { 68 | ULONG32 Exception; 69 | ULONG64 Address; 70 | } STATE_CHANGE_PACKET, *PSTATE_CHANGE_PACKET; 71 | 72 | typedef struct _READ_VIRTUAL_MEMORY_PACKET { 73 | ULONG64 Address; 74 | ULONG32 Size; 75 | } READ_VIRTUAL_MEMORY_PACKET, *PREAD_VIRTUAL_MEMORY_PACKET; 76 | 77 | typedef struct _WRITE_VIRTUAL_MEMORY_PACKET { 78 | ULONG64 Address; 79 | ULONG32 Size; 80 | } WRITE_VIRTUAL_MEMORY_PACKET, *PWRITE_VIRTUAL_MEMORY_PACKET; 81 | 82 | typedef struct _READ_PHYSICAL_MEMORY_PACKET { 83 | ULONG64 Address; 84 | ULONG32 Size; 85 | } READ_PHYSICAL_MEMORY_PACKET, *PREAD_PHYSICAL_MEMORY_PACKET; 86 | 87 | typedef struct _WRITE_PHYSICAL_MEMORY_PACKET { 88 | ULONG64 Address; 89 | ULONG32 Size; 90 | } WRITE_PHYSICAL_MEMORY_PACKET, *PWRITE_PHYSICAL_MEMORY_PACKET; 91 | 92 | typedef struct _DEBUG_CONTEXT { 93 | ULONG64 rax; 94 | ULONG64 rbx; 95 | ULONG64 rcx; 96 | ULONG64 rdx; 97 | ULONG64 rsi; 98 | ULONG64 rdi; 99 | ULONG64 rbp; 100 | ULONG64 rsp; 101 | ULONG64 r8; 102 | ULONG64 r9; 103 | ULONG64 r10; 104 | ULONG64 r11; 105 | ULONG64 r12; 106 | ULONG64 r13; 107 | ULONG64 r14; 108 | ULONG64 r15; 109 | ULONG64 rip; 110 | ULONG64 rflags; 111 | ULONG64 cr0; 112 | ULONG64 cr3; 113 | ULONG64 cr4; 114 | ULONG64 cr8; 115 | ULONG64 dr0; 116 | ULONG64 dr1; 117 | ULONG64 dr2; 118 | ULONG64 dr3; 119 | ULONG64 dr6; 120 | ULONG64 dr7; 121 | USHORT cs; 122 | USHORT ds; 123 | USHORT es; 124 | USHORT fs; 125 | USHORT ss; 126 | USHORT gs; 127 | } DEBUG_CONTEXT, *PDEBUG_CONTEXT; 128 | 129 | typedef struct _GET_CONTEXT_PACKET { 130 | ULONG32 Flags; 131 | } GET_CONTEXT_PACKET, *PGET_CONTEXT_PACKET; 132 | 133 | typedef struct _SET_CONTEXT_PACKET { 134 | ULONG32 Flags; 135 | } SET_CONTEXT_PACKET, *PSET_CONTEXT_PACKET; 136 | 137 | typedef struct _MANIPULATE_STATE_PACKET { 138 | ULONG32 ApiNumber; 139 | ULONG32 Error; 140 | union { 141 | READ_VIRTUAL_MEMORY_PACKET ReadVirtualMemory; 142 | WRITE_VIRTUAL_MEMORY_PACKET WriteVirtualMemory; 143 | READ_PHYSICAL_MEMORY_PACKET ReadPhysicalMemory; 144 | WRITE_PHYSICAL_MEMORY_PACKET WritePhysicalMemory; 145 | GET_CONTEXT_PACKET GetContext; 146 | SET_CONTEXT_PACKET SetContext; 147 | } u; 148 | } MANIPULATE_STATE_PACKET, *PMANIPULATE_STATE_PACKET; 149 | 150 | #define PACKET_TYPE_RESET 1 151 | #define PACKET_TYPE_BREAKIN 2 152 | #define PACKET_TYPE_ACK 3 153 | #define PACKET_TYPE_RESEND 4 154 | #define PACKET_TYPE_STATE_CHANGE 5 155 | #define PACKET_TYPE_MANIPULATE_STATE 6 156 | #define PACKET_TYPE_CONTINUE 7 157 | 158 | #define READ_VIRTUAL_MEMORY_API 0x41 159 | #define WRITE_VIRTUAL_MEMORY_API 0x42 160 | #define GET_CONTEXT_API 0x43 161 | #define SET_CONTEXT_API 0x44 162 | 163 | #define INITIAL_ID 0x41424344 164 | #define PACKET_MAGIC 0xdeadbabe 165 | 166 | #define MAX_PACKET_SIZE 0x800 167 | 168 | #define MAX_RETRIES 0x10000000 169 | 170 | NTSTATUS InitProtocolLayer(PVOID SendArea, PVOID RecvArea); 171 | PVOID ReceivePacket(); 172 | BOOLEAN SendPacket(PVOID pPacket, ULONG32 Retries); 173 | VOID DestroyPacket(PVOID pPacket); 174 | 175 | static PVOID CreateBreakinPacket(); 176 | PVOID CreateManipulateStatePacket(ULONG32 ApiNumber, ULONG32 Data2Size); 177 | PVOID CreateStateChangePacket(ULONG32 Exception, ULONG64 Address); 178 | static ULONG32 CalcChecksum(PVOID Src, ULONG32 Size); 179 | 180 | #endif 181 | -------------------------------------------------------------------------------- /src/virtdbg/snprintf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Patrick Powell 1995 3 | * This code is based on code written by Patrick Powell (papowell@astart.com) 4 | * It may be used for any purpose as long as this notice remains intact 5 | * on all source code distributions 6 | */ 7 | 8 | /************************************************************** 9 | * Original: 10 | * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 11 | * A bombproof version of doprnt (dopr) included. 12 | * Sigh. This sort of thing is always nasty do deal with. Note that 13 | * the version here does not include floating point... 14 | * 15 | * snprintf() is used instead of sprintf() as it does limit checks 16 | * for string length. This covers a nasty loophole. 17 | * 18 | * The other functions are there to prevent NULL pointers from 19 | * causing nast effects. 20 | * 21 | * More Recently: 22 | * Brandon Long 9/15/96 for mutt 0.43 23 | * This was ugly. It is still ugly. I opted out of floating point 24 | * numbers, but the formatter understands just about everything 25 | * from the normal C string format, at least as far as I can tell from 26 | * the Solaris 2.5 printf(3S) man page. 27 | * 28 | * Brandon Long 10/22/97 for mutt 0.87.1 29 | * Ok, added some minimal floating point support, which means this 30 | * probably requires libm on most operating systems. Don't yet 31 | * support the exponent (e,E) and sigfig (g,G). Also, fmtint() 32 | * was pretty badly broken, it just wasn't being exercised in ways 33 | * which showed it, so that's been fixed. Also, formated the code 34 | * to mutt conventions, and removed dead code left over from the 35 | * original. Also, there is now a builtin-test, just compile with: 36 | * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm 37 | * and run snprintf for results. 38 | * 39 | * Thomas Roessler 01/27/98 for mutt 0.89i 40 | * The PGP code was using unsigned hexadecimal formats. 41 | * Unfortunately, unsigned formats simply didn't work. 42 | * 43 | * Michael Elkins 03/05/98 for mutt 0.90.8 44 | * The original code assumed that both snprintf() and vsnprintf() were 45 | * missing. Some systems only have snprintf() but not vsnprintf(), so 46 | * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF. 47 | * 48 | * Andrew Tridgell (tridge@samba.org) Oct 1998 49 | * fixed handling of %.0f 50 | * added test for HAVE_LONG_DOUBLE 51 | * 52 | * tridge@samba.org, idra@samba.org, April 2001 53 | * got rid of fcvt code (twas buggy and made testing harder) 54 | * added C99 semantics 55 | * 56 | **************************************************************/ 57 | 58 | #define HAVE_STRING_H 59 | #define HAVE_CTYPE_H 60 | #define HAVE_STDLIB_H 61 | #define HAVE_LONG_LONG 62 | 63 | #ifdef HAVE_STRING_H 64 | # include 65 | #endif 66 | 67 | #ifdef HAVE_STRINGS_H 68 | # include 69 | #endif 70 | #ifdef HAVE_CTYPE_H 71 | # include 72 | #endif 73 | #include 74 | #include 75 | #ifdef HAVE_STDLIB_H 76 | # include 77 | #endif 78 | 79 | #if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF) 80 | /* only include stdio.h if we are not re-defining snprintf or vsnprintf */ 81 | # include 82 | /* make the compiler happy with an empty file */ 83 | void dummy_snprintf ( 84 | void 85 | ) 86 | { 87 | } 88 | #else 89 | 90 | # ifdef HAVE_LONG_LONG 91 | # define LLONG long long 92 | # else 93 | # define LLONG long 94 | # endif 95 | 96 | # ifdef isdigit 97 | # undef isdigit 98 | # endif 99 | # define isdigit(c) ((c) >= '0' && (c) <= '9') 100 | 101 | static size_t dopr ( 102 | char *buffer, 103 | size_t maxlen, 104 | const char *format, 105 | va_list args 106 | ); 107 | static void fmtstr ( 108 | char *buffer, 109 | size_t * currlen, 110 | size_t maxlen, 111 | char *value, 112 | int flags, 113 | int min, 114 | int max 115 | ); 116 | static void fmtint ( 117 | char *buffer, 118 | size_t * currlen, 119 | size_t maxlen, 120 | long long value, 121 | int base, 122 | int min, 123 | int max, 124 | int flags 125 | ); 126 | static void dopr_outch ( 127 | char *buffer, 128 | size_t * currlen, 129 | size_t maxlen, 130 | char c 131 | ); 132 | 133 | /* 134 | * dopr(): poor man's version of doprintf 135 | */ 136 | 137 | /* format read states */ 138 | # define DP_S_DEFAULT 0 139 | # define DP_S_FLAGS 1 140 | # define DP_S_MIN 2 141 | # define DP_S_DOT 3 142 | # define DP_S_MAX 4 143 | # define DP_S_MOD 5 144 | # define DP_S_CONV 6 145 | # define DP_S_DONE 7 146 | 147 | /* format flags - Bits */ 148 | # define DP_F_MINUS (1 << 0) 149 | # define DP_F_PLUS (1 << 1) 150 | # define DP_F_SPACE (1 << 2) 151 | # define DP_F_NUM (1 << 3) 152 | # define DP_F_ZERO (1 << 4) 153 | # define DP_F_UP (1 << 5) 154 | # define DP_F_UNSIGNED (1 << 6) 155 | 156 | /* Conversion Flags */ 157 | # define DP_C_SHORT 1 158 | # define DP_C_LONG 2 159 | # define DP_C_LDOUBLE 3 160 | # define DP_C_LLONG 4 161 | 162 | # define char_to_int(p) ((p)- '0') 163 | # ifndef MAX 164 | # define MAX(p,q) (((p) >= (q)) ? (p) : (q)) 165 | # endif 166 | 167 | static size_t dopr ( 168 | char *buffer, 169 | size_t maxlen, 170 | const char *format, 171 | va_list args 172 | ) 173 | { 174 | char ch; 175 | LLONG value; 176 | char *strvalue; 177 | int min; 178 | int max; 179 | int state; 180 | int flags; 181 | int cflags; 182 | size_t currlen; 183 | 184 | state = DP_S_DEFAULT; 185 | currlen = flags = cflags = min = 0; 186 | max = -1; 187 | ch = *format++; 188 | 189 | while (state != DP_S_DONE) { 190 | if (ch == '\0') 191 | state = DP_S_DONE; 192 | 193 | switch (state) { 194 | case DP_S_DEFAULT: 195 | if (ch == '%') 196 | state = DP_S_FLAGS; 197 | else 198 | dopr_outch (buffer, &currlen, maxlen, ch); 199 | ch = *format++; 200 | break; 201 | case DP_S_FLAGS: 202 | switch (ch) { 203 | case '-': 204 | flags |= DP_F_MINUS; 205 | ch = *format++; 206 | break; 207 | case '+': 208 | flags |= DP_F_PLUS; 209 | ch = *format++; 210 | break; 211 | case ' ': 212 | flags |= DP_F_SPACE; 213 | ch = *format++; 214 | break; 215 | case '#': 216 | flags |= DP_F_NUM; 217 | ch = *format++; 218 | break; 219 | case '0': 220 | flags |= DP_F_ZERO; 221 | ch = *format++; 222 | break; 223 | default: 224 | state = DP_S_MIN; 225 | break; 226 | } 227 | break; 228 | case DP_S_MIN: 229 | if (isdigit ((unsigned char) ch)) { 230 | min = 10 * min + char_to_int (ch); 231 | ch = *format++; 232 | } else if (ch == '*') { 233 | min = va_arg (args, int 234 | ); 235 | ch = *format++; 236 | state = DP_S_DOT; 237 | } else { 238 | state = DP_S_DOT; 239 | } 240 | break; 241 | case DP_S_DOT: 242 | if (ch == '.') { 243 | state = DP_S_MAX; 244 | ch = *format++; 245 | } else { 246 | state = DP_S_MOD; 247 | } 248 | break; 249 | case DP_S_MAX: 250 | if (isdigit ((unsigned char) ch)) { 251 | if (max < 0) 252 | max = 0; 253 | max = 10 * max + char_to_int (ch); 254 | ch = *format++; 255 | } else if (ch == '*') { 256 | max = va_arg (args, int 257 | ); 258 | ch = *format++; 259 | state = DP_S_MOD; 260 | } else { 261 | state = DP_S_MOD; 262 | } 263 | break; 264 | case DP_S_MOD: 265 | switch (ch) { 266 | case 'h': 267 | cflags = DP_C_SHORT; 268 | ch = *format++; 269 | break; 270 | case 'l': 271 | cflags = DP_C_LONG; 272 | ch = *format++; 273 | if (ch == 'l') { /* It's a long long */ 274 | cflags = DP_C_LLONG; 275 | ch = *format++; 276 | } 277 | break; 278 | case 'L': 279 | cflags = DP_C_LDOUBLE; 280 | ch = *format++; 281 | break; 282 | default: 283 | break; 284 | } 285 | state = DP_S_CONV; 286 | break; 287 | case DP_S_CONV: 288 | switch (ch) { 289 | case 'd': 290 | case 'i': 291 | if (cflags == DP_C_SHORT) 292 | value = va_arg (args, int 293 | ); 294 | else if (cflags == DP_C_LONG) 295 | value = va_arg (args, long int 296 | ); 297 | else if (cflags == DP_C_LLONG) 298 | value = va_arg (args, LLONG); 299 | else 300 | value = va_arg (args, int 301 | ); 302 | fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); 303 | break; 304 | case 'o': 305 | flags |= DP_F_UNSIGNED; 306 | if (cflags == DP_C_SHORT) 307 | value = va_arg (args, unsigned int 308 | ); 309 | else if (cflags == DP_C_LONG) 310 | value = (long) va_arg (args, unsigned long int 311 | ); 312 | else if (cflags == DP_C_LLONG) 313 | value = (long) va_arg (args, unsigned LLONG 314 | ); 315 | else 316 | value = (long) va_arg (args, unsigned int 317 | ); 318 | fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags); 319 | break; 320 | case 'u': 321 | flags |= DP_F_UNSIGNED; 322 | if (cflags == DP_C_SHORT) 323 | value = va_arg (args, unsigned int 324 | ); 325 | else if (cflags == DP_C_LONG) 326 | value = (long) va_arg (args, unsigned long int 327 | ); 328 | else if (cflags == DP_C_LLONG) 329 | value = (LLONG) va_arg (args, unsigned LLONG 330 | ); 331 | else 332 | value = (long) va_arg (args, unsigned int 333 | ); 334 | fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); 335 | break; 336 | case 'X': 337 | flags |= DP_F_UP; 338 | case 'x': 339 | flags |= DP_F_UNSIGNED; 340 | if (cflags == DP_C_SHORT) 341 | value = va_arg (args, unsigned int 342 | ); 343 | else if (cflags == DP_C_LONG) 344 | value = (long) va_arg (args, unsigned long int 345 | ); 346 | else if (cflags == DP_C_LLONG) 347 | value = (LLONG) va_arg (args, unsigned LLONG 348 | ); 349 | else 350 | value = (long) va_arg (args, unsigned int 351 | ); 352 | fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags); 353 | break; 354 | case 'f': 355 | break; 356 | case 'E': 357 | flags |= DP_F_UP; 358 | case 'e': 359 | break; 360 | case 'G': 361 | flags |= DP_F_UP; 362 | case 'g': 363 | break; 364 | case 'c': 365 | dopr_outch (buffer, &currlen, maxlen, va_arg (args, char) 366 | ); 367 | break; 368 | case 's': 369 | strvalue = va_arg (args, char * 370 | ); 371 | if (max == -1) { 372 | max = (int)strlen (strvalue); 373 | } 374 | if (min > 0 && max >= 0 && min > max) 375 | max = min; 376 | fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max); 377 | break; 378 | case 'p': 379 | flags |= DP_F_UNSIGNED | DP_F_UP; 380 | strvalue = va_arg (args, void * 381 | ); 382 | fmtint (buffer, &currlen, maxlen, (long long) strvalue, 16, min, max, flags); 383 | break; 384 | case 'n': 385 | if (cflags == DP_C_SHORT) { 386 | short int *num; 387 | num = va_arg (args, short int * 388 | ); 389 | *num = (short int) currlen; 390 | } else if (cflags == DP_C_LONG) { 391 | long int *num; 392 | num = va_arg (args, long int * 393 | ); 394 | *num = (long int) currlen; 395 | } else if (cflags == DP_C_LLONG) { 396 | LLONG *num; 397 | num = va_arg (args, LLONG *); 398 | *num = (LLONG) currlen; 399 | } else { 400 | int *num; 401 | num = va_arg (args, int * 402 | ); 403 | *num = (int)currlen; 404 | } 405 | break; 406 | case '%': 407 | dopr_outch (buffer, &currlen, maxlen, ch); 408 | break; 409 | case 'w': 410 | /* not supported yet, treat as next char */ 411 | ch = *format++; 412 | break; 413 | default: 414 | /* Unknown, skip */ 415 | break; 416 | } 417 | ch = *format++; 418 | state = DP_S_DEFAULT; 419 | flags = cflags = min = 0; 420 | max = -1; 421 | break; 422 | case DP_S_DONE: 423 | break; 424 | default: 425 | /* hmm? */ 426 | break; /* some picky compilers need this */ 427 | } 428 | } 429 | if (maxlen != 0) { 430 | if (currlen < maxlen - 1) 431 | buffer[currlen] = '\0'; 432 | else if (maxlen > 0) 433 | buffer[maxlen - 1] = '\0'; 434 | } 435 | 436 | return currlen; 437 | } 438 | 439 | static void fmtstr ( 440 | char *buffer, 441 | size_t * currlen, 442 | size_t maxlen, 443 | char *value, 444 | int flags, 445 | int min, 446 | int max 447 | ) 448 | { 449 | int padlen, strln; /* amount to pad */ 450 | int cnt = 0; 451 | 452 | # ifdef DEBUG_SNPRINTF 453 | printf ("fmtstr min=%d max=%d s=[%s]\n", min, max, value); 454 | # endif 455 | if (value == 0) { 456 | value = ""; 457 | } 458 | 459 | for (strln = 0; value[strln]; ++strln); /* strlen */ 460 | padlen = min - strln; 461 | if (padlen < 0) 462 | padlen = 0; 463 | if (flags & DP_F_MINUS) 464 | padlen = -padlen; /* Left Justify */ 465 | 466 | while ((padlen > 0) && (cnt < max)) { 467 | dopr_outch (buffer, currlen, maxlen, ' '); 468 | --padlen; 469 | ++cnt; 470 | } 471 | while (*value && (cnt < max)) { 472 | dopr_outch (buffer, currlen, maxlen, *value++); 473 | ++cnt; 474 | } 475 | while ((padlen < 0) && (cnt < max)) { 476 | dopr_outch (buffer, currlen, maxlen, ' '); 477 | ++padlen; 478 | ++cnt; 479 | } 480 | } 481 | 482 | /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ 483 | 484 | static void fmtint ( 485 | char *buffer, 486 | size_t * currlen, 487 | size_t maxlen, 488 | long long value, 489 | int base, 490 | int min, 491 | int max, 492 | int flags 493 | ) 494 | { 495 | int signvalue = 0; 496 | unsigned long long uvalue; 497 | char convert[20]; 498 | int place = 0; 499 | int spadlen = 0; /* amount to space pad */ 500 | int zpadlen = 0; /* amount to zero pad */ 501 | int caps = 0; 502 | 503 | if (max < 0) 504 | max = 0; 505 | 506 | uvalue = (unsigned long long) value; 507 | 508 | if (!(flags & DP_F_UNSIGNED)) { 509 | if (value < 0) { 510 | signvalue = '-'; 511 | uvalue = (unsigned long long) -value; 512 | } else { 513 | if (flags & DP_F_PLUS) /* Do a sign (+/i) */ 514 | signvalue = '+'; 515 | else if (flags & DP_F_SPACE) 516 | signvalue = ' '; 517 | } 518 | } 519 | 520 | if (flags & DP_F_UP) 521 | caps = 1; /* Should characters be upper case? */ 522 | 523 | do { 524 | convert[place++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef") 525 | [uvalue % (unsigned) base]; 526 | uvalue = (uvalue / (unsigned) base); 527 | } while (uvalue && (place < 20)); 528 | if (place == 20) 529 | place--; 530 | convert[place] = 0; 531 | 532 | zpadlen = max - place; 533 | spadlen = min - MAX (max, place) - (signvalue ? 1 : 0); 534 | if (zpadlen < 0) 535 | zpadlen = 0; 536 | if (spadlen < 0) 537 | spadlen = 0; 538 | if (flags & DP_F_ZERO) { 539 | zpadlen = MAX (zpadlen, spadlen); 540 | spadlen = 0; 541 | } 542 | if (flags & DP_F_MINUS) 543 | spadlen = -spadlen; /* Left Justifty */ 544 | 545 | # ifdef DEBUG_SNPRINTF 546 | printf ("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n", zpadlen, spadlen, min, max, place); 547 | # endif 548 | 549 | /* Spaces */ 550 | while (spadlen > 0) { 551 | dopr_outch (buffer, currlen, maxlen, ' '); 552 | --spadlen; 553 | } 554 | 555 | /* Sign */ 556 | if (signvalue) 557 | dopr_outch (buffer, currlen, maxlen, (char) signvalue); 558 | 559 | /* Zeros */ 560 | if (zpadlen > 0) { 561 | while (zpadlen > 0) { 562 | dopr_outch (buffer, currlen, maxlen, '0'); 563 | --zpadlen; 564 | } 565 | } 566 | 567 | /* Digits */ 568 | while (place > 0) 569 | dopr_outch (buffer, currlen, maxlen, convert[--place]); 570 | 571 | /* Left Justified spaces */ 572 | while (spadlen < 0) { 573 | dopr_outch (buffer, currlen, maxlen, ' '); 574 | ++spadlen; 575 | } 576 | } 577 | 578 | static void dopr_outch ( 579 | char *buffer, 580 | size_t * currlen, 581 | size_t maxlen, 582 | char c 583 | ) 584 | { 585 | if (*currlen < maxlen) { 586 | buffer[(*currlen)] = c; 587 | } 588 | (*currlen)++; 589 | } 590 | 591 | # if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF) 592 | int vsnprintf ( 593 | char *str, 594 | size_t count, 595 | const char *fmt, 596 | va_list args 597 | ) 598 | { 599 | return (int)dopr (str, count, fmt, args); 600 | } 601 | # endif 602 | 603 | # if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF) 604 | int snprintf ( 605 | char *str, 606 | size_t count, 607 | const char *fmt, 608 | ... 609 | ) 610 | { 611 | size_t ret; 612 | va_list ap; 613 | 614 | va_start (ap, fmt); 615 | ret = vsnprintf (str, count, fmt, ap); 616 | va_end (ap); 617 | return (int)ret; 618 | } 619 | # endif 620 | 621 | #endif 622 | -------------------------------------------------------------------------------- /src/virtdbg/snprintf.h: -------------------------------------------------------------------------------- 1 | #ifndef _PORTABLE_SNPRINTF_H_ 2 | # define _PORTABLE_SNPRINTF_H_ 3 | 4 | extern int snprintf ( 5 | char *, 6 | size_t, 7 | const char *, /*args */ 8 | ... 9 | ); 10 | extern int vsnprintf ( 11 | char *, 12 | size_t, 13 | const char *, 14 | va_list 15 | ); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/virtdbg/sources: -------------------------------------------------------------------------------- 1 | TARGETNAME=virtdbg 2 | TARGETTYPE=DRIVER 3 | TARGETPATH=..\..\build\virtdbg 4 | 5 | INCLUDES=. 6 | 7 | MSC_WARNING_LEVEL=/W4 /wd4201 /wd4214 /wd4100 8 | 9 | SOURCES=\ 10 | snprintf.c \ 11 | log.c \ 12 | mem.c \ 13 | debug.c \ 14 | protocol.c \ 15 | vmx.c \ 16 | virtdbg.c \ 17 | driver.c 18 | 19 | AMD64_SOURCES=\ 20 | amd64.asm 21 | 22 | -------------------------------------------------------------------------------- /src/virtdbg/virtdbg.c: -------------------------------------------------------------------------------- 1 | // This file is part of Virtdbg 2 | // Copyright (C) 2010-2011 Damien AUMAITRE 3 | 4 | // Licence is GPLv3, see LICENCE.txt in the top-level directory 5 | 6 | 7 | #include "virtdbg.h" 8 | 9 | static KMUTEX g_mutex; 10 | static LONG g_processors = 0; 11 | 12 | PVIRT_CPU *g_cpus = NULL; 13 | PVIRTDBG_CONTROL_AREA g_ControlArea = NULL; 14 | LONG g_Initialized = 0; 15 | 16 | static PVOID g_SendArea = NULL; 17 | static PVOID g_RecvArea = NULL; 18 | 19 | extern PVOID g_LogBuffer; 20 | 21 | NTSTATUS VirtDbgStart(PVOID StartContext) 22 | { 23 | NTSTATUS Status; 24 | CCHAR i; 25 | KIRQL OldIrql; 26 | KAFFINITY OldAffinity; 27 | 28 | InitLog(); 29 | 30 | Status = CheckForVirtualizationSupport(); 31 | if (Status == STATUS_UNSUCCESSFUL) 32 | { 33 | DbgLog(("aborting, no virtualisation support\n")); 34 | return STATUS_UNSUCCESSFUL; 35 | } 36 | 37 | KeInitializeMutex(&g_mutex, 0); 38 | KeWaitForSingleObject(&g_mutex, Executive, KernelMode, FALSE, NULL); 39 | DbgLog(("virtualizing %d processors ...\n", KeNumberProcessors)); 40 | 41 | g_cpus = ExAllocatePoolWithTag(NonPagedPool, KeNumberProcessors*sizeof(PVIRT_CPU), 0x42424242); 42 | 43 | if (!g_cpus) 44 | { 45 | DbgLog(("can't allocate cpus array\n")); 46 | return STATUS_INSUFFICIENT_RESOURCES; 47 | } 48 | 49 | DbgLog(("Allocated g_cpus array @ 0x%llx, size=0x%x\n", g_cpus, KeNumberProcessors*sizeof(PVIRT_CPU))); 50 | RtlZeroMemory(g_cpus, KeNumberProcessors*sizeof(PVIRT_CPU)); 51 | 52 | InitControlArea(); 53 | InitDebugLayer(); 54 | InitProtocolLayer(g_SendArea, g_RecvArea); 55 | 56 | for (i = 0; i < KeNumberProcessors; i++) 57 | { 58 | OldAffinity = KeSetSystemAffinityThreadEx((KAFFINITY) (1 << i)); 59 | OldIrql = KeRaiseIrqlToDpcLevel(); 60 | _StartVirtualization(); 61 | KeLowerIrql(OldIrql); 62 | KeRevertToUserAffinityThreadEx(OldAffinity); 63 | } 64 | 65 | DbgLog(("all done...\n")); 66 | 67 | KeReleaseMutex (&g_mutex, FALSE); 68 | 69 | if (KeNumberProcessors != g_processors) 70 | { 71 | DbgLog(("aborting, not all processors are virtualized\n")); 72 | return STATUS_UNSUCCESSFUL; 73 | } 74 | 75 | InterlockedIncrement(&g_Initialized); 76 | 77 | /* for (i = 0; i < KeNumberProcessors; i++)*/ 78 | /* {*/ 79 | /* DumpVirtCpu(g_cpus[i]);*/ 80 | /* }*/ 81 | 82 | return STATUS_SUCCESS; 83 | 84 | } 85 | 86 | NTSTATUS InitControlArea() 87 | { 88 | PHYSICAL_ADDRESS l1, l2, l3; 89 | 90 | l1.QuadPart = 0; 91 | l2.QuadPart = -1; 92 | l3.QuadPart = 0x200000; 93 | 94 | g_ControlArea = (PVIRTDBG_CONTROL_AREA)MmAllocateContiguousMemorySpecifyCache(CONTROL_AREA_SIZE, 95 | l1, l2, l3, MmCached); 96 | 97 | if (g_ControlArea == NULL) 98 | return STATUS_NO_MEMORY; 99 | 100 | DbgLog(("Allocated CONTROL_AREA structure @ 0x%llx\n", g_ControlArea)); 101 | l1 = MmGetPhysicalAddress(g_ControlArea); 102 | DbgLog(("CONTROL_AREA phys @ 0x%llx\n", l1.QuadPart)); 103 | 104 | RtlZeroMemory(g_ControlArea, CONTROL_AREA_SIZE); 105 | 106 | g_ControlArea->Magic1 = CONTROL_AREA_MAGIC1; 107 | g_ControlArea->Magic2 = CONTROL_AREA_MAGIC2; 108 | 109 | g_SendArea = AllocateMemory(0x1000); 110 | 111 | if (g_SendArea == NULL) 112 | return STATUS_NO_MEMORY; 113 | 114 | g_ControlArea->SendArea = MmGetPhysicalAddress(g_SendArea); 115 | 116 | g_RecvArea = AllocateMemory(0x1000); 117 | 118 | if (g_RecvArea == NULL) 119 | return STATUS_NO_MEMORY; 120 | 121 | g_ControlArea->RecvArea = MmGetPhysicalAddress(g_RecvArea); 122 | 123 | g_ControlArea->KernelBase = FindNtoskrnlBase(ZwClose); 124 | g_ControlArea->DebuggerData = 0; 125 | g_ControlArea->LogBuffer = MmGetPhysicalAddress(g_LogBuffer); 126 | 127 | return STATUS_SUCCESS; 128 | } 129 | 130 | #define IMAGE_DOS_SIGNATURE 0x5a4d 131 | 132 | static PVOID FindNtoskrnlBase(PVOID Addr) 133 | { 134 | /// Scandown from a given symbol’s address. 135 | Addr = (PVOID)((ULONG_PTR)Addr & ~0xfff); 136 | __try { 137 | while ((*(PUSHORT)Addr != IMAGE_DOS_SIGNATURE)) { 138 | Addr = (PVOID) ((ULONG_PTR)Addr - PAGE_SIZE); 139 | } 140 | return Addr; 141 | } 142 | __except(1) { } 143 | return NULL; 144 | } 145 | 146 | NTSTATUS StartVirtualization(PVOID GuestRsp) 147 | { 148 | NTSTATUS Status; 149 | PVOID HostKernelStackBase; 150 | PVIRT_CPU pCpu; 151 | 152 | Status = CheckIfVMXIsEnabled(); 153 | 154 | if (Status == STATUS_UNSUCCESSFUL) 155 | { 156 | return STATUS_UNSUCCESSFUL; 157 | } 158 | 159 | HostKernelStackBase = ExAllocatePoolWithTag(NonPagedPool, 16*0x1000, 0x42424242); 160 | RtlZeroMemory(HostKernelStackBase, 16*0x1000); 161 | if (!HostKernelStackBase) 162 | { 163 | DbgLog(("can't allocate host kernel stack\n")); 164 | return STATUS_INSUFFICIENT_RESOURCES; 165 | } 166 | 167 | pCpu = (PVIRT_CPU)((PCHAR)HostKernelStackBase+16*0x1000-8-sizeof(VIRT_CPU)); 168 | pCpu->HostKernelStackBase = HostKernelStackBase; 169 | pCpu->Self = pCpu; 170 | pCpu->State = STATE_RUNNING; 171 | pCpu->Mailbox = IPI_RUNNING; 172 | 173 | Status = SetupVMX(pCpu); 174 | 175 | g_cpus[pCpu->ProcessorNumber] = pCpu; 176 | 177 | if (Status == STATUS_UNSUCCESSFUL) 178 | { 179 | return STATUS_UNSUCCESSFUL; 180 | } 181 | 182 | Status = SetupVMCS(pCpu, GuestRsp); 183 | 184 | if (Status == STATUS_UNSUCCESSFUL) 185 | { 186 | return STATUS_UNSUCCESSFUL; 187 | } 188 | 189 | InterlockedIncrement(&g_processors); 190 | 191 | Status = Virtualize(pCpu); 192 | 193 | if (Status == STATUS_UNSUCCESSFUL) 194 | { 195 | return STATUS_UNSUCCESSFUL; 196 | } 197 | 198 | return STATUS_SUCCESS; 199 | } 200 | 201 | -------------------------------------------------------------------------------- /src/virtdbg/virtdbg.h: -------------------------------------------------------------------------------- 1 | // This file is part of Virtdbg 2 | // Copyright (C) 2010-2011 Damien AUMAITRE 3 | 4 | // Licence is GPLv3, see LICENCE.txt in the top-level directory 5 | 6 | 7 | #ifndef _VIRTDBG_MAIN_H 8 | #define _VIRTDBG_MAIN_H 9 | 10 | #include 11 | #include "amd64.h" 12 | #include "vmx.h" 13 | #include "mem.h" 14 | #include "debug.h" 15 | #include "misc.h" 16 | #include "protocol.h" 17 | 18 | NTSTATUS VirtDbgStart(PVOID StartContext); 19 | NTSTATUS InitControlArea(); 20 | NTSTATUS StartVirtualization(PVOID GuestRsp); 21 | static PVOID FindNtoskrnlBase(PVOID Addr); 22 | 23 | #endif 24 | 25 | -------------------------------------------------------------------------------- /src/virtdbg/vmx.c: -------------------------------------------------------------------------------- 1 | // This file is part of Virtdbg 2 | // Copyright (C) 2010-2011 Damien AUMAITRE 3 | 4 | // Licence is GPLv3, see LICENCE.txt in the top-level directory 5 | 6 | 7 | #include "vmx.h" 8 | 9 | 10 | VOID DumpVirtCpu(PVIRT_CPU pCpu) 11 | { 12 | DbgLog(("pCpu @ %p\n", pCpu)); 13 | DbgLog(("pCpu->Self=0x%llx\n", pCpu->Self)); 14 | DbgLog(("pCpu->ProcessorNumber=0x%lx\n", pCpu->ProcessorNumber)); 15 | DbgLog(("pCpu->State=0x%lx\n", pCpu->State)); 16 | DbgLog(("pCpu->Mailbox=0x%lx\n", pCpu->Mailbox)); 17 | } 18 | 19 | BOOLEAN IsBitSet(ULONG64 v, UCHAR bitNo) 20 | { 21 | ULONG64 mask = (ULONG64) 1 << bitNo; 22 | return (BOOLEAN) ((v & mask) != 0); 23 | } 24 | 25 | 26 | VOID DumpGuestRegs(PGUEST_REGS pGuestRegs) 27 | { 28 | DbgPrint("rax=0x%llx\n", pGuestRegs->rax); 29 | DbgPrint("rbx=0x%llx\n", pGuestRegs->rbx); 30 | DbgPrint("rcx=0x%llx\n", pGuestRegs->rcx); 31 | DbgPrint("rdx=0x%llx\n", pGuestRegs->rdx); 32 | DbgPrint("rbp=0x%llx\n", pGuestRegs->rbp); 33 | DbgPrint("rsp=0x%llx\n", pGuestRegs->rsp); 34 | DbgPrint("rdi=0x%llx\n", pGuestRegs->rdi); 35 | DbgPrint("rsi=0x%llx\n", pGuestRegs->rsi); 36 | DbgPrint("r8=0x%llx\n", pGuestRegs->r8); 37 | DbgPrint("r9=0x%llx\n", pGuestRegs->r9); 38 | DbgPrint("r10=0x%llx\n", pGuestRegs->r10); 39 | DbgPrint("r11=0x%llx\n", pGuestRegs->r11); 40 | DbgPrint("r12=0x%llx\n", pGuestRegs->r12); 41 | DbgPrint("r13=0x%llx\n", pGuestRegs->r13); 42 | DbgPrint("r14=0x%llx\n", pGuestRegs->r14); 43 | DbgPrint("r15=0x%llx\n", pGuestRegs->r15); 44 | } 45 | 46 | NTSTATUS InitializeSegmentSelector(PSEGMENT_SELECTOR SegmentSelector, 47 | USHORT Selector, PUCHAR GdtBase) 48 | { 49 | PSEGMENT_DESCRIPTOR SegDesc; 50 | ULONG64 tmp; 51 | 52 | if (!SegmentSelector) 53 | return STATUS_INVALID_PARAMETER; 54 | 55 | if (Selector & 0x4) { 56 | DbgPrint("InitializeSegmentSelector(): Given selector (0x%X) points to LDT\n", Selector); 57 | return STATUS_INVALID_PARAMETER; 58 | } 59 | 60 | SegDesc = (PSEGMENT_DESCRIPTOR) ((PUCHAR) GdtBase + (Selector & ~0x7)); 61 | 62 | SegmentSelector->sel = Selector; 63 | SegmentSelector->base = SegDesc->base0 | SegDesc->base1 << 16 | SegDesc->base2 << 24; 64 | SegmentSelector->limit = SegDesc->limit0 | (SegDesc->limit1attr1 & 0xf) << 16; 65 | SegmentSelector->attributes.UCHARs = SegDesc->attr0 | (SegDesc->limit1attr1 & 0xf0) << 4; 66 | 67 | if (!(SegDesc->attr0 & LA_STANDARD)) { 68 | // this is a TSS or callgate etc, save the base high part 69 | tmp = (*(PULONG64) ((PUCHAR) SegDesc + 8)); 70 | SegmentSelector->base = (SegmentSelector->base & 0xffffffff) | (tmp << 32); 71 | } 72 | 73 | if (SegmentSelector->attributes.fields.g) { 74 | // 4096-bit granularity is enabled for this segment, scale the limit 75 | SegmentSelector->limit = (SegmentSelector->limit << 12) + 0xfff; 76 | } 77 | 78 | return STATUS_SUCCESS; 79 | } 80 | 81 | ULONG32 AdjustControls(ULONG32 Ctl, ULONG32 Msr) 82 | { 83 | LARGE_INTEGER MsrValue; 84 | MsrValue.QuadPart = _ReadMsr(Msr); 85 | DbgLog(("Adjusting control for msr 0x%x\n", Msr)); 86 | DbgLog(("Adjusting controls (low): 0x%08x\n", MsrValue.LowPart)); 87 | DbgLog(("Adjusting controls (high): 0x%08x\n", MsrValue.HighPart)); 88 | Ctl &= MsrValue.HighPart; 89 | Ctl |= MsrValue.LowPart; 90 | return Ctl; 91 | } 92 | 93 | 94 | NTSTATUS CheckForVirtualizationSupport() 95 | { 96 | ULONG32 eax, ebx, ecx, edx; 97 | /* vmx supported by cpu ? */ 98 | _CpuId(0, &eax, &ebx, &ecx, &edx); 99 | if (eax < 1) 100 | { 101 | DbgLog(("error: extended CPUID functions not implemented\n")); 102 | return STATUS_UNSUCCESSFUL; 103 | } 104 | 105 | /* Intel Genuine */ 106 | if (!(ebx == 0x756e6547 && ecx == 0x6c65746e && edx == 0x49656e69)) 107 | { 108 | DbgLog(("error: not an INTEL processor\n")); 109 | return STATUS_UNSUCCESSFUL; 110 | } 111 | 112 | _CpuId(0x1, &eax, &ebx, &ecx, &edx); 113 | if (!IsBitSet(ecx, 5)) 114 | { 115 | DbgLog(("error: VMX not supported\n")); 116 | return STATUS_UNSUCCESSFUL; 117 | } 118 | 119 | return STATUS_SUCCESS; 120 | } 121 | 122 | NTSTATUS ResumeGuest() 123 | { 124 | DbgLog(("Resuming guest...\n")); 125 | return STATUS_SUCCESS; 126 | } 127 | 128 | NTSTATUS FillGuestSelectorData(PVOID GdtBase, ULONG Segreg, USHORT 129 | Selector) 130 | { 131 | SEGMENT_SELECTOR SegmentSelector = { 0 }; 132 | ULONG uAccessRights; 133 | 134 | InitializeSegmentSelector(&SegmentSelector, Selector, GdtBase); 135 | uAccessRights = ((PUCHAR) & SegmentSelector.attributes)[0] + (((PUCHAR) & 136 | SegmentSelector.attributes)[1] << 12); 137 | 138 | if (!Selector) 139 | uAccessRights |= 0x10000; 140 | 141 | _WriteVMCS(GUEST_ES_SELECTOR + Segreg * 2, Selector); 142 | _WriteVMCS(GUEST_ES_LIMIT + Segreg * 2, SegmentSelector.limit); 143 | _WriteVMCS(GUEST_ES_AR_BYTES + Segreg * 2, uAccessRights); 144 | 145 | if ((Segreg == LDTR) || (Segreg == TR)) 146 | // don't setup for FS/GS - their bases are stored in MSR values 147 | _WriteVMCS(GUEST_ES_BASE + Segreg * 2, SegmentSelector.base); 148 | 149 | return STATUS_SUCCESS; 150 | } 151 | 152 | NTSTATUS SetupVMCS(PVIRT_CPU pCpu, PVOID GuestRsp) 153 | { 154 | ULONG32 Interceptions, ExceptionBitmap; 155 | PVOID GdtBase; 156 | SEGMENT_SELECTOR SegmentSelector; 157 | ULONG32 i; 158 | PHYSICAL_ADDRESS pa; 159 | 160 | i = KeGetCurrentProcessorNumber(); 161 | DbgLog(("GuestRsp=%p\n", GuestRsp)); 162 | 163 | pa = pCpu->VMCS_pa; 164 | DbgLog(("VMCS PHYSICAL_ADDRESS %llx\n", pa)); 165 | _VmClear(pa); 166 | _VmPtrLd(pa); 167 | 168 | _WriteVMCS(GUEST_CR0, _Cr0()); 169 | _WriteVMCS(GUEST_CR3, _Cr3()); 170 | _WriteVMCS(GUEST_CR4, _Cr4()); 171 | _WriteVMCS(GUEST_DR7, 0x400); 172 | _WriteVMCS(GUEST_RSP, (ULONG64)GuestRsp); 173 | _WriteVMCS(GUEST_RIP, (ULONG64)_GuestEntryPoint); 174 | _WriteVMCS(GUEST_RFLAGS, _Rflags()); 175 | 176 | GdtBase = (PVOID) _GdtBase(); 177 | FillGuestSelectorData(GdtBase, ES, _Es()); 178 | FillGuestSelectorData(GdtBase, CS, _Cs()); 179 | FillGuestSelectorData(GdtBase, SS, _Ss()); 180 | FillGuestSelectorData(GdtBase, DS, _Ds()); 181 | FillGuestSelectorData(GdtBase, FS, _Fs()); 182 | FillGuestSelectorData(GdtBase, GS, _Gs()); 183 | FillGuestSelectorData(GdtBase, LDTR, _Ldtr()); 184 | FillGuestSelectorData(GdtBase, TR, _TrSelector()); 185 | _WriteVMCS(GUEST_ES_BASE, 0); 186 | _WriteVMCS(GUEST_CS_BASE, 0); 187 | _WriteVMCS(GUEST_SS_BASE, 0); 188 | _WriteVMCS(GUEST_DS_BASE, 0); 189 | _WriteVMCS(GUEST_FS_BASE, _ReadMsr(MSR_FS_BASE)); 190 | _WriteVMCS(GUEST_GS_BASE, _ReadMsr(MSR_GS_BASE)); 191 | _WriteVMCS(GUEST_GDTR_BASE, (ULONG64) GdtBase); 192 | _WriteVMCS(GUEST_IDTR_BASE, _IdtBase()); 193 | _WriteVMCS(GUEST_GDTR_LIMIT, _GdtLimit()); 194 | _WriteVMCS(GUEST_IDTR_LIMIT, _IdtLimit()); 195 | 196 | _WriteVMCS(GUEST_IA32_DEBUGCTL, _ReadMsr(MSR_IA32_DEBUGCTL) & 0xffffffff); 197 | _WriteVMCS(GUEST_IA32_DEBUGCTL_HIGH, _ReadMsr(MSR_IA32_DEBUGCTL) >> 32); 198 | _WriteVMCS(GUEST_SYSENTER_CS, _ReadMsr(MSR_IA32_SYSENTER_CS)); 199 | _WriteVMCS(GUEST_SYSENTER_ESP, _ReadMsr(MSR_IA32_SYSENTER_ESP)); 200 | _WriteVMCS(GUEST_SYSENTER_EIP, _ReadMsr(MSR_IA32_SYSENTER_EIP)); 201 | 202 | /* guest non register state */ 203 | _WriteVMCS(GUEST_INTERRUPTIBILITY_INFO, 0); 204 | _WriteVMCS(GUEST_ACTIVITY_STATE, 0); 205 | _WriteVMCS(VMCS_LINK_POINTER, 0xffffffff); 206 | _WriteVMCS(VMCS_LINK_POINTER_HIGH, 0xffffffff); 207 | 208 | /* host state area */ 209 | _WriteVMCS(HOST_CR0, _Cr0()); 210 | _WriteVMCS(HOST_CR3, _Cr3()); 211 | _WriteVMCS(HOST_CR4, _Cr4()); 212 | _WriteVMCS(HOST_RSP, (ULONG64) pCpu); 213 | _WriteVMCS(HOST_RIP, (ULONG64) _ExitHandler); 214 | 215 | _WriteVMCS(HOST_ES_SELECTOR, KGDT64_R0_DATA); 216 | _WriteVMCS(HOST_CS_SELECTOR, KGDT64_R0_CODE); 217 | _WriteVMCS(HOST_SS_SELECTOR, KGDT64_R0_DATA); 218 | _WriteVMCS(HOST_DS_SELECTOR, KGDT64_R0_DATA); 219 | _WriteVMCS(HOST_FS_SELECTOR, (_Fs() & 0xf8)); 220 | _WriteVMCS(HOST_GS_SELECTOR, (_Gs() & 0xf8)); 221 | _WriteVMCS(HOST_TR_SELECTOR, (_TrSelector() & 0xf8)); 222 | _WriteVMCS(HOST_FS_BASE, _ReadMsr(MSR_FS_BASE)); 223 | _WriteVMCS(HOST_GS_BASE, _ReadMsr(MSR_GS_BASE)); 224 | 225 | InitializeSegmentSelector(&SegmentSelector, _TrSelector(), (PVOID) 226 | _GdtBase()); 227 | 228 | _WriteVMCS(HOST_TR_BASE, SegmentSelector.base); 229 | 230 | _WriteVMCS(HOST_GDTR_BASE, _GdtBase()); 231 | _WriteVMCS(HOST_IDTR_BASE, _IdtBase()); 232 | 233 | _WriteVMCS(HOST_IA32_SYSENTER_ESP, _ReadMsr(MSR_IA32_SYSENTER_ESP)); 234 | _WriteVMCS(HOST_IA32_SYSENTER_EIP, _ReadMsr(MSR_IA32_SYSENTER_EIP)); 235 | _WriteVMCS(HOST_IA32_SYSENTER_CS, _ReadMsr(MSR_IA32_SYSENTER_CS)); 236 | 237 | /* VM Execution Control Fields */ 238 | _WriteVMCS(PIN_BASED_VM_EXEC_CONTROL, AdjustControls(0, 239 | MSR_IA32_VMX_PINBASED_CTLS)); 240 | 241 | Interceptions = 0; 242 | Interceptions |= CPU_BASED_ACTIVATE_MSR_BITMAP; 243 | _WriteVMCS(CPU_BASED_VM_EXEC_CONTROL, AdjustControls(Interceptions, 244 | MSR_IA32_VMX_PROCBASED_CTLS)); 245 | 246 | ExceptionBitmap = 0; 247 | ExceptionBitmap |= 1<MSR_bitmap_pa.LowPart); 261 | _WriteVMCS(MSR_BITMAP_HIGH, pCpu->MSR_bitmap_pa.HighPart); 262 | 263 | /* VM Exit Control */ 264 | _WriteVMCS(VM_EXIT_CONTROLS, AdjustControls(VM_EXIT_IA32E_MODE | 265 | VM_EXIT_ACK_INTR_ON_EXIT, MSR_IA32_VMX_EXIT_CTLS)); 266 | 267 | _WriteVMCS(VM_EXIT_MSR_STORE_COUNT, 0); 268 | _WriteVMCS(VM_EXIT_MSR_LOAD_COUNT, 0); 269 | _WriteVMCS(VM_ENTRY_CONTROLS, AdjustControls(VM_ENTRY_IA32E_MODE, 270 | MSR_IA32_VMX_ENTRY_CTLS)); 271 | 272 | _WriteVMCS(VM_ENTRY_MSR_LOAD_COUNT, 0); 273 | _WriteVMCS(VM_ENTRY_INTR_INFO_FIELD, 0); 274 | 275 | _WriteVMCS(CR0_GUEST_HOST_MASK, X86_CR0_PG); 276 | _WriteVMCS(CR0_READ_SHADOW, (_Cr0() & X86_CR0_PG) | X86_CR0_PG); 277 | 278 | _WriteVMCS(CR4_GUEST_HOST_MASK, X86_CR4_VMXE); 279 | _WriteVMCS(CR4_READ_SHADOW, 0); 280 | 281 | _WriteVMCS(CR3_TARGET_COUNT, 0); 282 | _WriteVMCS(CR3_TARGET_VALUE0, 0); //no use 283 | _WriteVMCS(CR3_TARGET_VALUE1, 0); //no use 284 | _WriteVMCS(CR3_TARGET_VALUE2, 0); //no use 285 | _WriteVMCS(CR3_TARGET_VALUE3, 0); //no use 286 | 287 | return STATUS_SUCCESS; 288 | } 289 | 290 | NTSTATUS SetupVMX(PVIRT_CPU pCpu) 291 | { 292 | PHYSICAL_ADDRESS pa; 293 | ULONG64 msr; 294 | PVMX_BASIC_MSR pvmx; 295 | ULONG32 i; 296 | PVOID va; 297 | ULONG size; 298 | 299 | i = KeGetCurrentProcessorNumber(); 300 | 301 | pCpu->ProcessorNumber = i; 302 | msr = _ReadMsr(MSR_IA32_VMX_BASIC); 303 | pvmx = (PVMX_BASIC_MSR)&msr; 304 | 305 | size = pvmx->szVmxOnRegion; 306 | 307 | DbgLog(("VMXON region size: 0x%x\n", size)); 308 | DbgLog(("VMX revision ID: 0x%x\n", pvmx->RevId)); 309 | 310 | va = AllocateContiguousMemory(size); 311 | 312 | if (va == NULL) 313 | { 314 | DbgLog(("error: can't allocate vmxon region\n")); 315 | return STATUS_INSUFFICIENT_RESOURCES; 316 | } 317 | 318 | *(ULONG32 *)va = pvmx->RevId; 319 | pa = MmGetPhysicalAddress(va); 320 | 321 | _VmxOn(pa); 322 | 323 | if (_VmFailInvalid()) 324 | { 325 | DbgLog(("_VmxOn failed\n")); 326 | return STATUS_UNSUCCESSFUL; 327 | } 328 | 329 | pCpu->VMXON_va = va; 330 | pCpu->VMXON_pa = pa; 331 | 332 | va = AllocateContiguousMemory(size); 333 | 334 | if (va == NULL) 335 | { 336 | DbgLog(("error: can't allocate vmcs region\n")); 337 | return STATUS_INSUFFICIENT_RESOURCES; 338 | } 339 | 340 | *(ULONG32 *)va = pvmx->RevId; 341 | pa = MmGetPhysicalAddress(va); 342 | 343 | pCpu->VMCS_va = va; 344 | pCpu->VMCS_pa = pa; 345 | 346 | va = AllocateContiguousMemory(0x1000); 347 | pa = MmGetPhysicalAddress(va); 348 | 349 | if (va == NULL) 350 | { 351 | DbgLog(("error: can't allocate msr bitmap\n")); 352 | return STATUS_INSUFFICIENT_RESOURCES; 353 | } 354 | 355 | pCpu->MSR_bitmap_va = va; 356 | pCpu->MSR_bitmap_pa = pa; 357 | 358 | return STATUS_SUCCESS; 359 | } 360 | 361 | NTSTATUS CheckIfVMXIsEnabled() 362 | { 363 | ULONG64 cr4, msr; 364 | 365 | /* vmxon supported ? */ 366 | _SetCr4(X86_CR4_VMXE); 367 | cr4 = _Cr4(); 368 | 369 | if (!(cr4 & X86_CR4_VMXE)) 370 | { 371 | DbgLog(("error: VMXON not supported\n")); 372 | return STATUS_UNSUCCESSFUL; 373 | } 374 | 375 | /* vmx desactived by bios ? */ 376 | msr = _ReadMsr(MSR_IA32_FEATURE_CONTROL); 377 | if (!(msr & 4)) 378 | { 379 | DbgLog(("vmx is disabled in bios: MSR_IA32_FEATURE_CONTROL is 0x%llx\n", msr)); 380 | return STATUS_UNSUCCESSFUL; 381 | } 382 | 383 | return STATUS_SUCCESS; 384 | } 385 | 386 | 387 | NTSTATUS Virtualize(PVIRT_CPU pCpu) 388 | { 389 | /* ULONG64 rsp;*/ 390 | ULONG32 i; 391 | 392 | i = KeGetCurrentProcessorNumber(); 393 | DbgLog(("CPU: 0x%p \n", pCpu)); 394 | DbgLog(("rsp: 0x%llx \n", _Rsp())); 395 | 396 | _VmLaunch(); 397 | /* never returns if successful */ 398 | DbgLog(("rflags after _VmLaunch: 0x%x\n", _Rflags())); 399 | if (_VmFailInvalid()) 400 | { 401 | DbgLog(("no current VMCS\n")); 402 | return STATUS_UNSUCCESSFUL; 403 | } 404 | 405 | if (_VmFailValid()) 406 | { 407 | DbgLog(("vmlaunch failed\n")); 408 | DbgLog(("_ReadVMCS: 0x%llx\n", _ReadVMCS(VM_INSTRUCTION_ERROR))); 409 | return STATUS_UNSUCCESSFUL; 410 | } 411 | 412 | return STATUS_UNSUCCESSFUL; 413 | } 414 | 415 | 416 | 417 | 418 | 419 | -------------------------------------------------------------------------------- /src/virtdbg/vmx.h: -------------------------------------------------------------------------------- 1 | // This file is part of Virtdbg 2 | // Copyright (C) 2010-2011 Damien AUMAITRE 3 | 4 | // Licence is GPLv3, see LICENCE.txt in the top-level directory 5 | 6 | 7 | #ifndef _VIRTDBG_VMX_H 8 | #define _VIRTDBG_VMX_H 9 | 10 | #include 11 | #include "amd64.h" 12 | #include "misc.h" 13 | #include "mem.h" 14 | 15 | typedef struct _VIRT_CPU { 16 | PVOID Self; 17 | ULONG32 ProcessorNumber; 18 | PVOID VMXON_va; 19 | PHYSICAL_ADDRESS VMXON_pa; 20 | PVOID VMCS_va; 21 | PHYSICAL_ADDRESS VMCS_pa; 22 | PVOID HostKernelStackBase; 23 | PVOID MSR_bitmap_va; 24 | PHYSICAL_ADDRESS MSR_bitmap_pa; 25 | ULONG32 State; 26 | ULONG32 Mailbox; 27 | } VIRT_CPU, *PVIRT_CPU; 28 | 29 | #define STATE_RUNNING 1 30 | #define STATE_FROZEN 2 31 | #define STATE_BREAKIN 3 32 | #define STATE_DEBUGGED 4 33 | 34 | #define IPI_FREEZE 1 35 | #define IPI_FROZEN 2 36 | #define IPI_RESUME 3 37 | #define IPI_RUNNING 4 38 | 39 | /* 40 | * VMX Exit Reasons 41 | */ 42 | 43 | #define VMX_EXIT_REASONS_FAILED_VMENTRY 0x80000000 44 | 45 | #define EXIT_REASON_EXCEPTION_NMI 0 46 | #define EXIT_REASON_EXTERNAL_INTERRUPT 1 47 | #define EXIT_REASON_TRIPLE_FAULT 2 48 | #define EXIT_REASON_INIT 3 49 | #define EXIT_REASON_SIPI 4 50 | #define EXIT_REASON_IO_SMI 5 51 | #define EXIT_REASON_OTHER_SMI 6 52 | #define EXIT_REASON_PENDING_INTERRUPT 7 53 | 54 | #define EXIT_REASON_TASK_SWITCH 9 55 | #define EXIT_REASON_CPUID 10 56 | #define EXIT_REASON_HLT 12 57 | #define EXIT_REASON_INVD 13 58 | #define EXIT_REASON_INVLPG 14 59 | #define EXIT_REASON_RDPMC 15 60 | #define EXIT_REASON_RDTSC 16 61 | #define EXIT_REASON_RSM 17 62 | #define EXIT_REASON_VMCALL 18 63 | #define EXIT_REASON_VMCLEAR 19 64 | #define EXIT_REASON_VMLAUNCH 20 65 | #define EXIT_REASON_VMPTRLD 21 66 | #define EXIT_REASON_VMPTRST 22 67 | #define EXIT_REASON_VMREAD 23 68 | #define EXIT_REASON_VMRESUME 24 69 | #define EXIT_REASON_VMWRITE 25 70 | #define EXIT_REASON_VMXOFF 26 71 | #define EXIT_REASON_VMXON 27 72 | #define EXIT_REASON_CR_ACCESS 28 73 | #define EXIT_REASON_DR_ACCESS 29 74 | #define EXIT_REASON_IO_INSTRUCTION 30 75 | #define EXIT_REASON_MSR_READ 31 76 | #define EXIT_REASON_MSR_WRITE 32 77 | 78 | #define EXIT_REASON_INVALID_GUEST_STATE 33 79 | #define EXIT_REASON_MSR_LOADING 34 80 | 81 | #define EXIT_REASON_MWAIT_INSTRUCTION 36 82 | #define EXIT_REASON_MONITOR_INSTRUCTION 39 83 | #define EXIT_REASON_PAUSE_INSTRUCTION 40 84 | 85 | #define EXIT_REASON_MACHINE_CHECK 41 86 | 87 | #define EXIT_REASON_TPR_BELOW_THRESHOLD 43 88 | 89 | #define VMX_MAX_GUEST_VMEXIT EXIT_REASON_TPR_BELOW_THRESHOLD 90 | 91 | typedef struct _MOV_CR_QUALIFICATION { 92 | unsigned ControlRegister:4; 93 | unsigned AccessType:2; 94 | unsigned LMSWOperandType:1; 95 | unsigned Reserved1:1; 96 | unsigned Register:4; 97 | unsigned Reserved2:4; 98 | unsigned LMSWSourceData:16; 99 | unsigned Reserved3:32; 100 | } MOV_CR_QUALIFICATION, *PMOV_CR_QUALIFICATION; 101 | 102 | typedef struct _INTERRUPT_INFO_FIELD { 103 | unsigned Vector:8; 104 | unsigned InterruptionType:3; 105 | unsigned ErrorCodeValid:1; 106 | unsigned NMIUnblocking:1; 107 | unsigned Reserved:18; 108 | unsigned Valid:1; 109 | } INTERRUPT_INFO_FIELD, *PINTERRUPT_INFO_FIELD; 110 | 111 | typedef struct _INTERRUPT_INJECT_INFO_FIELD{ 112 | unsigned Vector:8; 113 | unsigned InterruptionType:3; 114 | unsigned DeliverErrorCode:1; 115 | unsigned Reserved:19; 116 | unsigned Valid:1; 117 | } INTERRUPT_INJECT_INFO_FIELD, *PINTERRUPT_INJECT_INFO_FIELD; 118 | 119 | typedef struct _DEBUG_EXIT_QUALIFICATION { 120 | unsigned B0:1; 121 | unsigned B1:1; 122 | unsigned B2:1; 123 | unsigned B3:1; 124 | unsigned Reserved:9; 125 | unsigned BD:1; 126 | unsigned BS:1; 127 | unsigned Reserved2:17; 128 | unsigned Reserved3:32; 129 | } DEBUG_EXIT_QUALIFICATION, *PDEBUG_EXIT_QUALIFICATION; 130 | 131 | 132 | #define MOV_TO_CR 0 133 | #define MOV_FROM_CR 1 134 | #define CLTS 2 135 | #define LMSW 3 136 | 137 | #define CPU_BASED_VIRTUAL_INTR_PENDING 0x00000004 138 | #define CPU_BASED_USE_TSC_OFFSETING 0x00000008 139 | #define CPU_BASED_HLT_EXITING 0x00000080 140 | #define CPU_BASED_INVDPG_EXITING 0x00000200 141 | #define CPU_BASED_MWAIT_EXITING 0x00000400 142 | #define CPU_BASED_RDPMC_EXITING 0x00000800 143 | #define CPU_BASED_RDTSC_EXITING 0x00001000 144 | #define CPU_BASED_CR8_LOAD_EXITING 0x00080000 145 | #define CPU_BASED_CR8_STORE_EXITING 0x00100000 146 | #define CPU_BASED_TPR_SHADOW 0x00200000 147 | #define CPU_BASED_MOV_DR_EXITING 0x00800000 148 | #define CPU_BASED_UNCOND_IO_EXITING 0x01000000 149 | #define CPU_BASED_ACTIVATE_IO_BITMAP 0x02000000 150 | #define CPU_BASED_ACTIVATE_MSR_BITMAP 0x10000000 151 | #define CPU_BASED_MONITOR_EXITING 0x20000000 152 | #define CPU_BASED_PAUSE_EXITING 0x40000000 153 | 154 | #define PIN_BASED_EXT_INTR_MASK 0x00000001 155 | #define PIN_BASED_NMI_EXITING 0x00000008 156 | 157 | #define VM_EXIT_IA32E_MODE 0x00000200 158 | #define VM_EXIT_ACK_INTR_ON_EXIT 0x00008000 159 | 160 | #define VM_ENTRY_IA32E_MODE 0x00000200 161 | #define VM_ENTRY_SMM 0x00000400 162 | #define VM_ENTRY_DEACT_DUAL_MONITOR 0x00000800 163 | 164 | /* VMCS Encodings */ 165 | enum { 166 | GUEST_ES_SELECTOR = 0x00000800, 167 | GUEST_CS_SELECTOR = 0x00000802, 168 | GUEST_SS_SELECTOR = 0x00000804, 169 | GUEST_DS_SELECTOR = 0x00000806, 170 | GUEST_FS_SELECTOR = 0x00000808, 171 | GUEST_GS_SELECTOR = 0x0000080a, 172 | GUEST_LDTR_SELECTOR = 0x0000080c, 173 | GUEST_TR_SELECTOR = 0x0000080e, 174 | HOST_ES_SELECTOR = 0x00000c00, 175 | HOST_CS_SELECTOR = 0x00000c02, 176 | HOST_SS_SELECTOR = 0x00000c04, 177 | HOST_DS_SELECTOR = 0x00000c06, 178 | HOST_FS_SELECTOR = 0x00000c08, 179 | HOST_GS_SELECTOR = 0x00000c0a, 180 | HOST_TR_SELECTOR = 0x00000c0c, 181 | IO_BITMAP_A = 0x00002000, 182 | IO_BITMAP_A_HIGH = 0x00002001, 183 | IO_BITMAP_B = 0x00002002, 184 | IO_BITMAP_B_HIGH = 0x00002003, 185 | MSR_BITMAP = 0x00002004, 186 | MSR_BITMAP_HIGH = 0x00002005, 187 | VM_EXIT_MSR_STORE_ADDR = 0x00002006, 188 | VM_EXIT_MSR_STORE_ADDR_HIGH = 0x00002007, 189 | VM_EXIT_MSR_LOAD_ADDR = 0x00002008, 190 | VM_EXIT_MSR_LOAD_ADDR_HIGH = 0x00002009, 191 | VM_ENTRY_MSR_LOAD_ADDR = 0x0000200a, 192 | VM_ENTRY_MSR_LOAD_ADDR_HIGH = 0x0000200b, 193 | TSC_OFFSET = 0x00002010, 194 | TSC_OFFSET_HIGH = 0x00002011, 195 | VIRTUAL_APIC_PAGE_ADDR = 0x00002012, 196 | VIRTUAL_APIC_PAGE_ADDR_HIGH = 0x00002013, 197 | VMCS_LINK_POINTER = 0x00002800, 198 | VMCS_LINK_POINTER_HIGH = 0x00002801, 199 | GUEST_IA32_DEBUGCTL = 0x00002802, 200 | GUEST_IA32_DEBUGCTL_HIGH = 0x00002803, 201 | PIN_BASED_VM_EXEC_CONTROL = 0x00004000, 202 | CPU_BASED_VM_EXEC_CONTROL = 0x00004002, 203 | EXCEPTION_BITMAP = 0x00004004, 204 | PAGE_FAULT_ERROR_CODE_MASK = 0x00004006, 205 | PAGE_FAULT_ERROR_CODE_MATCH = 0x00004008, 206 | CR3_TARGET_COUNT = 0x0000400a, 207 | VM_EXIT_CONTROLS = 0x0000400c, 208 | VM_EXIT_MSR_STORE_COUNT = 0x0000400e, 209 | VM_EXIT_MSR_LOAD_COUNT = 0x00004010, 210 | VM_ENTRY_CONTROLS = 0x00004012, 211 | VM_ENTRY_MSR_LOAD_COUNT = 0x00004014, 212 | VM_ENTRY_INTR_INFO_FIELD = 0x00004016, 213 | VM_ENTRY_EXCEPTION_ERROR_CODE = 0x00004018, 214 | VM_ENTRY_INSTRUCTION_LEN = 0x0000401a, 215 | TPR_THRESHOLD = 0x0000401c, 216 | SECONDARY_VM_EXEC_CONTROL = 0x0000401e, 217 | VM_INSTRUCTION_ERROR = 0x00004400, 218 | VM_EXIT_REASON = 0x00004402, 219 | VM_EXIT_INTR_INFO = 0x00004404, 220 | VM_EXIT_INTR_ERROR_CODE = 0x00004406, 221 | IDT_VECTORING_INFO_FIELD = 0x00004408, 222 | IDT_VECTORING_ERROR_CODE = 0x0000440a, 223 | VM_EXIT_INSTRUCTION_LEN = 0x0000440c, 224 | VMX_INSTRUCTION_INFO = 0x0000440e, 225 | GUEST_ES_LIMIT = 0x00004800, 226 | GUEST_CS_LIMIT = 0x00004802, 227 | GUEST_SS_LIMIT = 0x00004804, 228 | GUEST_DS_LIMIT = 0x00004806, 229 | GUEST_FS_LIMIT = 0x00004808, 230 | GUEST_GS_LIMIT = 0x0000480a, 231 | GUEST_LDTR_LIMIT = 0x0000480c, 232 | GUEST_TR_LIMIT = 0x0000480e, 233 | GUEST_GDTR_LIMIT = 0x00004810, 234 | GUEST_IDTR_LIMIT = 0x00004812, 235 | GUEST_ES_AR_BYTES = 0x00004814, 236 | GUEST_CS_AR_BYTES = 0x00004816, 237 | GUEST_SS_AR_BYTES = 0x00004818, 238 | GUEST_DS_AR_BYTES = 0x0000481a, 239 | GUEST_FS_AR_BYTES = 0x0000481c, 240 | GUEST_GS_AR_BYTES = 0x0000481e, 241 | GUEST_LDTR_AR_BYTES = 0x00004820, 242 | GUEST_TR_AR_BYTES = 0x00004822, 243 | GUEST_INTERRUPTIBILITY_INFO = 0x00004824, 244 | GUEST_ACTIVITY_STATE = 0x00004826, 245 | GUEST_SM_BASE = 0x00004828, 246 | GUEST_SYSENTER_CS = 0x0000482A, 247 | HOST_IA32_SYSENTER_CS = 0x00004c00, 248 | CR0_GUEST_HOST_MASK = 0x00006000, 249 | CR4_GUEST_HOST_MASK = 0x00006002, 250 | CR0_READ_SHADOW = 0x00006004, 251 | CR4_READ_SHADOW = 0x00006006, 252 | CR3_TARGET_VALUE0 = 0x00006008, 253 | CR3_TARGET_VALUE1 = 0x0000600a, 254 | CR3_TARGET_VALUE2 = 0x0000600c, 255 | CR3_TARGET_VALUE3 = 0x0000600e, 256 | EXIT_QUALIFICATION = 0x00006400, 257 | GUEST_LINEAR_ADDRESS = 0x0000640a, 258 | GUEST_CR0 = 0x00006800, 259 | GUEST_CR3 = 0x00006802, 260 | GUEST_CR4 = 0x00006804, 261 | GUEST_ES_BASE = 0x00006806, 262 | GUEST_CS_BASE = 0x00006808, 263 | GUEST_SS_BASE = 0x0000680a, 264 | GUEST_DS_BASE = 0x0000680c, 265 | GUEST_FS_BASE = 0x0000680e, 266 | GUEST_GS_BASE = 0x00006810, 267 | GUEST_LDTR_BASE = 0x00006812, 268 | GUEST_TR_BASE = 0x00006814, 269 | GUEST_GDTR_BASE = 0x00006816, 270 | GUEST_IDTR_BASE = 0x00006818, 271 | GUEST_DR7 = 0x0000681a, 272 | GUEST_RSP = 0x0000681c, 273 | GUEST_RIP = 0x0000681e, 274 | GUEST_RFLAGS = 0x00006820, 275 | GUEST_PENDING_DBG_EXCEPTIONS = 0x00006822, 276 | GUEST_SYSENTER_ESP = 0x00006824, 277 | GUEST_SYSENTER_EIP = 0x00006826, 278 | HOST_CR0 = 0x00006c00, 279 | HOST_CR3 = 0x00006c02, 280 | HOST_CR4 = 0x00006c04, 281 | HOST_FS_BASE = 0x00006c06, 282 | HOST_GS_BASE = 0x00006c08, 283 | HOST_TR_BASE = 0x00006c0a, 284 | HOST_GDTR_BASE = 0x00006c0c, 285 | HOST_IDTR_BASE = 0x00006c0e, 286 | HOST_IA32_SYSENTER_ESP = 0x00006c10, 287 | HOST_IA32_SYSENTER_EIP = 0x00006c12, 288 | HOST_RSP = 0x00006c14, 289 | HOST_RIP = 0x00006c16, 290 | }; 291 | 292 | typedef struct { 293 | ULONG64 GUEST_ES_SELECTOR; 294 | ULONG64 GUEST_CS_SELECTOR; 295 | ULONG64 GUEST_SS_SELECTOR; 296 | ULONG64 GUEST_DS_SELECTOR; 297 | ULONG64 GUEST_FS_SELECTOR; 298 | ULONG64 GUEST_GS_SELECTOR; 299 | ULONG64 GUEST_LDTR_SELECTOR; 300 | ULONG64 GUEST_TR_SELECTOR; 301 | ULONG64 HOST_ES_SELECTOR; 302 | ULONG64 HOST_CS_SELECTOR; 303 | ULONG64 HOST_SS_SELECTOR; 304 | ULONG64 HOST_DS_SELECTOR; 305 | ULONG64 HOST_FS_SELECTOR; 306 | ULONG64 HOST_GS_SELECTOR; 307 | ULONG64 HOST_TR_SELECTOR; 308 | ULONG64 IO_BITMAP_A; 309 | ULONG64 IO_BITMAP_A_HIGH; 310 | ULONG64 IO_BITMAP_B; 311 | ULONG64 IO_BITMAP_B_HIGH; 312 | ULONG64 MSR_BITMAP; 313 | ULONG64 MSR_BITMAP_HIGH; 314 | ULONG64 VM_EXIT_MSR_STORE_ADDR; 315 | ULONG64 VM_EXIT_MSR_STORE_ADDR_HIGH; 316 | ULONG64 VM_EXIT_MSR_LOAD_ADDR; 317 | ULONG64 VM_EXIT_MSR_LOAD_ADDR_HIGH; 318 | ULONG64 VM_ENTRY_MSR_LOAD_ADDR; 319 | ULONG64 VM_ENTRY_MSR_LOAD_ADDR_HIGH; 320 | ULONG64 TSC_OFFSET; 321 | ULONG64 TSC_OFFSET_HIGH; 322 | ULONG64 VIRTUAL_APIC_PAGE_ADDR; 323 | ULONG64 VIRTUAL_APIC_PAGE_ADDR_HIGH; 324 | ULONG64 VMCS_LINK_POINTER; 325 | ULONG64 VMCS_LINK_POINTER_HIGH; 326 | ULONG64 GUEST_IA32_DEBUGCTL; 327 | ULONG64 GUEST_IA32_DEBUGCTL_HIGH; 328 | ULONG64 PIN_BASED_VM_EXEC_CONTROL; 329 | ULONG64 CPU_BASED_VM_EXEC_CONTROL; 330 | ULONG64 EXCEPTION_BITMAP; 331 | ULONG64 PAGE_FAULT_ERROR_CODE_MASK; 332 | ULONG64 PAGE_FAULT_ERROR_CODE_MATCH; 333 | ULONG64 CR3_TARGET_COUNT; 334 | ULONG64 VM_EXIT_CONTROLS; 335 | ULONG64 VM_EXIT_MSR_STORE_COUNT; 336 | ULONG64 VM_EXIT_MSR_LOAD_COUNT; 337 | ULONG64 VM_ENTRY_CONTROLS; 338 | ULONG64 VM_ENTRY_MSR_LOAD_COUNT; 339 | ULONG64 VM_ENTRY_INTR_INFO_FIELD; 340 | ULONG64 VM_ENTRY_EXCEPTION_ERROR_CODE; 341 | ULONG64 VM_ENTRY_INSTRUCTION_LEN; 342 | ULONG64 TPR_THRESHOLD; 343 | ULONG64 SECONDARY_VM_EXEC_CONTROL; 344 | ULONG64 VM_INSTRUCTION_ERROR; 345 | ULONG64 VM_EXIT_REASON; 346 | ULONG64 VM_EXIT_INTR_INFO; 347 | ULONG64 VM_EXIT_INTR_ERROR_CODE; 348 | ULONG64 IDT_VECTORING_INFO_FIELD; 349 | ULONG64 IDT_VECTORING_ERROR_CODE; 350 | ULONG64 VM_EXIT_INSTRUCTION_LEN; 351 | ULONG64 VMX_INSTRUCTION_INFO; 352 | ULONG64 GUEST_ES_LIMIT; 353 | ULONG64 GUEST_CS_LIMIT; 354 | ULONG64 GUEST_SS_LIMIT; 355 | ULONG64 GUEST_DS_LIMIT; 356 | ULONG64 GUEST_FS_LIMIT; 357 | ULONG64 GUEST_GS_LIMIT; 358 | ULONG64 GUEST_LDTR_LIMIT; 359 | ULONG64 GUEST_TR_LIMIT; 360 | ULONG64 GUEST_GDTR_LIMIT; 361 | ULONG64 GUEST_IDTR_LIMIT; 362 | ULONG64 GUEST_ES_AR_BYTES; 363 | ULONG64 GUEST_CS_AR_BYTES; 364 | ULONG64 GUEST_SS_AR_BYTES; 365 | ULONG64 GUEST_DS_AR_BYTES; 366 | ULONG64 GUEST_FS_AR_BYTES; 367 | ULONG64 GUEST_GS_AR_BYTES; 368 | ULONG64 GUEST_LDTR_AR_BYTES; 369 | ULONG64 GUEST_TR_AR_BYTES; 370 | ULONG64 GUEST_INTERRUPTIBILITY_INFO; 371 | ULONG64 GUEST_ACTIVITY_STATE; 372 | ULONG64 GUEST_SM_BASE; 373 | ULONG64 GUEST_SYSENTER_CS; 374 | ULONG64 HOST_IA32_SYSENTER_CS; 375 | ULONG64 CR0_GUEST_HOST_MASK; 376 | ULONG64 CR4_GUEST_HOST_MASK; 377 | ULONG64 CR0_READ_SHADOW; 378 | ULONG64 CR4_READ_SHADOW; 379 | ULONG64 CR3_TARGET_VALUE0; 380 | ULONG64 CR3_TARGET_VALUE1; 381 | ULONG64 CR3_TARGET_VALUE2; 382 | ULONG64 CR3_TARGET_VALUE3; 383 | ULONG64 EXIT_QUALIFICATION; 384 | ULONG64 GUEST_LINEAR_ADDRESS; 385 | ULONG64 GUEST_CR0; 386 | ULONG64 GUEST_CR3; 387 | ULONG64 GUEST_CR4; 388 | ULONG64 GUEST_ES_BASE; 389 | ULONG64 GUEST_CS_BASE; 390 | ULONG64 GUEST_SS_BASE; 391 | ULONG64 GUEST_DS_BASE; 392 | ULONG64 GUEST_FS_BASE; 393 | ULONG64 GUEST_GS_BASE; 394 | ULONG64 GUEST_LDTR_BASE; 395 | ULONG64 GUEST_TR_BASE; 396 | ULONG64 GUEST_GDTR_BASE; 397 | ULONG64 GUEST_IDTR_BASE; 398 | ULONG64 GUEST_DR7; 399 | ULONG64 GUEST_RSP; 400 | ULONG64 GUEST_RIP; 401 | ULONG64 GUEST_RFLAGS; 402 | ULONG64 GUEST_PENDING_DBG_EXCEPTIONS; 403 | ULONG64 GUEST_SYSENTER_ESP; 404 | ULONG64 GUEST_SYSENTER_EIP; 405 | ULONG64 HOST_CR0; 406 | ULONG64 HOST_CR3; 407 | ULONG64 HOST_CR4; 408 | ULONG64 HOST_FS_BASE; 409 | ULONG64 HOST_GS_BASE; 410 | ULONG64 HOST_TR_BASE; 411 | ULONG64 HOST_GDTR_BASE; 412 | ULONG64 HOST_IDTR_BASE; 413 | ULONG64 HOST_IA32_SYSENTER_ESP; 414 | ULONG64 HOST_IA32_SYSENTER_EIP; 415 | ULONG64 HOST_RSP; 416 | ULONG64 HOST_RIP; 417 | } VMCS, *PVMCS; 418 | 419 | ULONG32 AdjustControls(ULONG32 Ctl, ULONG32 Msr); 420 | VOID DumpGuestRegs(PGUEST_REGS pGuestRegs); 421 | 422 | BOOLEAN IsBitSet(ULONG64 v, UCHAR bitNo); 423 | NTSTATUS InitializeSegmentSelector(PSEGMENT_SELECTOR SegmentSelector, 424 | USHORT Selector, PUCHAR GdtBase); 425 | 426 | 427 | NTSTATUS CheckForVirtualizationSupport(); 428 | NTSTATUS ResumeGuest(); 429 | NTSTATUS FillGuestSelectorData(PVOID GdtBase, ULONG Segreg, USHORT 430 | Selector); 431 | NTSTATUS SetupVMCS(PVIRT_CPU pCpu, PVOID GuestRsp); 432 | NTSTATUS SetupVMX(PVIRT_CPU pCpu); 433 | NTSTATUS CheckIfVMXIsEnabled(); 434 | 435 | NTSTATUS Virtualize(PVIRT_CPU pCpu); 436 | VOID StopVirtualization(); 437 | 438 | VOID DumpVirtCpu(PVIRT_CPU pCpu); 439 | 440 | 441 | #endif 442 | 443 | --------------------------------------------------------------------------------