├── LICENSE.md ├── README.md ├── windpl.py ├── windpl_extra.py └── windpl_loop.py /LICENSE.md: -------------------------------------------------------------------------------- 1 | ### GNU GENERAL PUBLIC LICENSE 2 | 3 | Version 3, 29 June 2007 4 | 5 | Copyright (C) 2007 Free Software Foundation, Inc. 6 | 7 | 8 | Everyone is permitted to copy and distribute verbatim copies of this 9 | license document, but changing it is not allowed. 10 | 11 | ### Preamble 12 | 13 | The GNU General Public License is a free, copyleft license for 14 | software and other kinds of works. 15 | 16 | The licenses for most software and other practical works are designed 17 | to take away your freedom to share and change the works. By contrast, 18 | the GNU General Public License is intended to guarantee your freedom 19 | to share and change all versions of a program--to make sure it remains 20 | free software for all its users. We, the Free Software Foundation, use 21 | the GNU General Public License for most of our software; it applies 22 | also to any other work released this way by its authors. You can apply 23 | it to your programs, too. 24 | 25 | When we speak of free software, we are referring to freedom, not 26 | price. Our General Public Licenses are designed to make sure that you 27 | have the freedom to distribute copies of free software (and charge for 28 | them if you wish), that you receive source code or can get it if you 29 | want it, that you can change the software or use pieces of it in new 30 | free programs, and that you know you can do these things. 31 | 32 | To protect your rights, we need to prevent others from denying you 33 | these rights or asking you to surrender the rights. Therefore, you 34 | have certain responsibilities if you distribute copies of the 35 | software, or if you modify it: responsibilities to respect the freedom 36 | of others. 37 | 38 | For example, if you distribute copies of such a program, whether 39 | gratis or for a fee, you must pass on to the recipients the same 40 | freedoms that you received. You must make sure that they, too, receive 41 | or can get the source code. And you must show them these terms so they 42 | know their rights. 43 | 44 | Developers that use the GNU GPL protect your rights with two steps: 45 | (1) assert copyright on the software, and (2) offer you this License 46 | giving you legal permission to copy, distribute and/or modify it. 47 | 48 | For the developers' and authors' protection, the GPL clearly explains 49 | that there is no warranty for this free software. For both users' and 50 | authors' sake, the GPL requires that modified versions be marked as 51 | changed, so that their problems will not be attributed erroneously to 52 | authors of previous versions. 53 | 54 | Some devices are designed to deny users access to install or run 55 | modified versions of the software inside them, although the 56 | manufacturer can do so. This is fundamentally incompatible with the 57 | aim of protecting users' freedom to change the software. The 58 | systematic pattern of such abuse occurs in the area of products for 59 | individuals to use, which is precisely where it is most unacceptable. 60 | Therefore, we have designed this version of the GPL to prohibit the 61 | practice for those products. If such problems arise substantially in 62 | other domains, we stand ready to extend this provision to those 63 | domains in future versions of the GPL, as needed to protect the 64 | freedom of users. 65 | 66 | Finally, every program is threatened constantly by software patents. 67 | States should not allow patents to restrict development and use of 68 | software on general-purpose computers, but in those that do, we wish 69 | to avoid the special danger that patents applied to a free program 70 | could make it effectively proprietary. To prevent this, the GPL 71 | assures that patents cannot be used to render the program non-free. 72 | 73 | The precise terms and conditions for copying, distribution and 74 | modification follow. 75 | 76 | ### TERMS AND CONDITIONS 77 | 78 | #### 0. Definitions. 79 | 80 | "This License" refers to version 3 of the GNU General Public License. 81 | 82 | "Copyright" also means copyright-like laws that apply to other kinds 83 | of works, such as semiconductor masks. 84 | 85 | "The Program" refers to any copyrightable work licensed under this 86 | License. Each licensee is addressed as "you". "Licensees" and 87 | "recipients" may be individuals or organizations. 88 | 89 | To "modify" a work means to copy from or adapt all or part of the work 90 | in a fashion requiring copyright permission, other than the making of 91 | an exact copy. The resulting work is called a "modified version" of 92 | the earlier work or a work "based on" the earlier work. 93 | 94 | A "covered work" means either the unmodified Program or a work based 95 | on the Program. 96 | 97 | To "propagate" a work means to do anything with it that, without 98 | permission, would make you directly or secondarily liable for 99 | infringement under applicable copyright law, except executing it on a 100 | computer or modifying a private copy. Propagation includes copying, 101 | distribution (with or without modification), making available to the 102 | public, and in some countries other activities as well. 103 | 104 | To "convey" a work means any kind of propagation that enables other 105 | parties to make or receive copies. Mere interaction with a user 106 | through a computer network, with no transfer of a copy, is not 107 | conveying. 108 | 109 | An interactive user interface displays "Appropriate Legal Notices" to 110 | the extent that it includes a convenient and prominently visible 111 | feature that (1) displays an appropriate copyright notice, and (2) 112 | tells the user that there is no warranty for the work (except to the 113 | extent that warranties are provided), that licensees may convey the 114 | work under this License, and how to view a copy of this License. If 115 | the interface presents a list of user commands or options, such as a 116 | menu, a prominent item in the list meets this criterion. 117 | 118 | #### 1. Source Code. 119 | 120 | The "source code" for a work means the preferred form of the work for 121 | making modifications to it. "Object code" means any non-source form of 122 | a work. 123 | 124 | A "Standard Interface" means an interface that either is an official 125 | standard defined by a recognized standards body, or, in the case of 126 | interfaces specified for a particular programming language, one that 127 | is widely used among developers working in that language. 128 | 129 | The "System Libraries" of an executable work include anything, other 130 | than the work as a whole, that (a) is included in the normal form of 131 | packaging a Major Component, but which is not part of that Major 132 | Component, and (b) serves only to enable use of the work with that 133 | Major Component, or to implement a Standard Interface for which an 134 | implementation is available to the public in source code form. A 135 | "Major Component", in this context, means a major essential component 136 | (kernel, window system, and so on) of the specific operating system 137 | (if any) on which the executable work runs, or a compiler used to 138 | produce the work, or an object code interpreter used to run it. 139 | 140 | The "Corresponding Source" for a work in object code form means all 141 | the source code needed to generate, install, and (for an executable 142 | work) run the object code and to modify the work, including scripts to 143 | control those activities. However, it does not include the work's 144 | System Libraries, or general-purpose tools or generally available free 145 | programs which are used unmodified in performing those activities but 146 | which are not part of the work. For example, Corresponding Source 147 | includes interface definition files associated with source files for 148 | the work, and the source code for shared libraries and dynamically 149 | linked subprograms that the work is specifically designed to require, 150 | such as by intimate data communication or control flow between those 151 | subprograms and other parts of the work. 152 | 153 | The Corresponding Source need not include anything that users can 154 | regenerate automatically from other parts of the Corresponding Source. 155 | 156 | The Corresponding Source for a work in source code form is that same 157 | work. 158 | 159 | #### 2. Basic Permissions. 160 | 161 | All rights granted under this License are granted for the term of 162 | copyright on the Program, and are irrevocable provided the stated 163 | conditions are met. This License explicitly affirms your unlimited 164 | permission to run the unmodified Program. The output from running a 165 | covered work is covered by this License only if the output, given its 166 | content, constitutes a covered work. This License acknowledges your 167 | rights of fair use or other equivalent, as provided by copyright law. 168 | 169 | You may make, run and propagate covered works that you do not convey, 170 | without conditions so long as your license otherwise remains in force. 171 | You may convey covered works to others for the sole purpose of having 172 | them make modifications exclusively for you, or provide you with 173 | facilities for running those works, provided that you comply with the 174 | terms of this License in conveying all material for which you do not 175 | control copyright. Those thus making or running the covered works for 176 | you must do so exclusively on your behalf, under your direction and 177 | control, on terms that prohibit them from making any copies of your 178 | copyrighted material outside their relationship with you. 179 | 180 | Conveying under any other circumstances is permitted solely under the 181 | conditions stated below. Sublicensing is not allowed; section 10 makes 182 | it unnecessary. 183 | 184 | #### 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 185 | 186 | No covered work shall be deemed part of an effective technological 187 | measure under any applicable law fulfilling obligations under article 188 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 189 | similar laws prohibiting or restricting circumvention of such 190 | measures. 191 | 192 | When you convey a covered work, you waive any legal power to forbid 193 | circumvention of technological measures to the extent such 194 | circumvention is effected by exercising rights under this License with 195 | respect to the covered work, and you disclaim any intention to limit 196 | operation or modification of the work as a means of enforcing, against 197 | the work's users, your or third parties' legal rights to forbid 198 | circumvention of technological measures. 199 | 200 | #### 4. Conveying Verbatim Copies. 201 | 202 | You may convey verbatim copies of the Program's source code as you 203 | receive it, in any medium, provided that you conspicuously and 204 | appropriately publish on each copy an appropriate copyright notice; 205 | keep intact all notices stating that this License and any 206 | non-permissive terms added in accord with section 7 apply to the code; 207 | keep intact all notices of the absence of any warranty; and give all 208 | recipients a copy of this License along with the Program. 209 | 210 | You may charge any price or no price for each copy that you convey, 211 | and you may offer support or warranty protection for a fee. 212 | 213 | #### 5. Conveying Modified Source Versions. 214 | 215 | You may convey a work based on the Program, or the modifications to 216 | produce it from the Program, in the form of source code under the 217 | terms of section 4, provided that you also meet all of these 218 | conditions: 219 | 220 | - a) The work must carry prominent notices stating that you modified 221 | it, and giving a relevant date. 222 | - b) The work must carry prominent notices stating that it is 223 | released under this License and any conditions added under 224 | section 7. This requirement modifies the requirement in section 4 225 | to "keep intact all notices". 226 | - c) You must license the entire work, as a whole, under this 227 | License to anyone who comes into possession of a copy. This 228 | License will therefore apply, along with any applicable section 7 229 | additional terms, to the whole of the work, and all its parts, 230 | regardless of how they are packaged. This License gives no 231 | permission to license the work in any other way, but it does not 232 | invalidate such permission if you have separately received it. 233 | - d) If the work has interactive user interfaces, each must display 234 | Appropriate Legal Notices; however, if the Program has interactive 235 | interfaces that do not display Appropriate Legal Notices, your 236 | work need not make them do so. 237 | 238 | A compilation of a covered work with other separate and independent 239 | works, which are not by their nature extensions of the covered work, 240 | and which are not combined with it such as to form a larger program, 241 | in or on a volume of a storage or distribution medium, is called an 242 | "aggregate" if the compilation and its resulting copyright are not 243 | used to limit the access or legal rights of the compilation's users 244 | beyond what the individual works permit. Inclusion of a covered work 245 | in an aggregate does not cause this License to apply to the other 246 | parts of the aggregate. 247 | 248 | #### 6. Conveying Non-Source Forms. 249 | 250 | You may convey a covered work in object code form under the terms of 251 | sections 4 and 5, provided that you also convey the machine-readable 252 | Corresponding Source under the terms of this License, in one of these 253 | ways: 254 | 255 | - a) Convey the object code in, or embodied in, a physical product 256 | (including a physical distribution medium), accompanied by the 257 | Corresponding Source fixed on a durable physical medium 258 | customarily used for software interchange. 259 | - b) Convey the object code in, or embodied in, a physical product 260 | (including a physical distribution medium), accompanied by a 261 | written offer, valid for at least three years and valid for as 262 | long as you offer spare parts or customer support for that product 263 | model, to give anyone who possesses the object code either (1) a 264 | copy of the Corresponding Source for all the software in the 265 | product that is covered by this License, on a durable physical 266 | medium customarily used for software interchange, for a price no 267 | more than your reasonable cost of physically performing this 268 | conveying of source, or (2) access to copy the Corresponding 269 | Source from a network server at no charge. 270 | - c) Convey individual copies of the object code with a copy of the 271 | written offer to provide the Corresponding Source. This 272 | alternative is allowed only occasionally and noncommercially, and 273 | only if you received the object code with such an offer, in accord 274 | with subsection 6b. 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 | - e) Convey the object code using peer-to-peer transmission, 288 | provided you inform other peers where the object code and 289 | Corresponding Source of the work are being offered to the general 290 | public at no charge under subsection 6d. 291 | 292 | A separable portion of the object code, whose source code is excluded 293 | from the Corresponding Source as a System Library, need not be 294 | included in conveying the object code work. 295 | 296 | A "User Product" is either (1) a "consumer product", which means any 297 | tangible personal property which is normally used for personal, 298 | family, or household purposes, or (2) anything designed or sold for 299 | incorporation into a dwelling. In determining whether a product is a 300 | consumer product, doubtful cases shall be resolved in favor of 301 | coverage. For a particular product received by a particular user, 302 | "normally used" refers to a typical or common use of that class of 303 | product, regardless of the status of the particular user or of the way 304 | in which the particular user actually uses, or expects or is expected 305 | to use, the product. A product is a consumer product regardless of 306 | whether the product has substantial commercial, industrial or 307 | non-consumer uses, unless such uses represent the only significant 308 | 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 312 | install and execute modified versions of a covered work in that User 313 | Product from a modified version of its Corresponding Source. The 314 | information must suffice to ensure that the continued functioning of 315 | the modified object code is in no case prevented or interfered with 316 | solely because 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 331 | updates for a work that has been modified or installed by the 332 | recipient, or for the User Product in which it has been modified or 333 | installed. Access to a network may be denied when the modification 334 | itself materially and adversely affects the operation of the network 335 | or violates the rules and protocols for communication across the 336 | network. 337 | 338 | Corresponding Source conveyed, and Installation Information provided, 339 | in accord with this section must be in a format that is publicly 340 | documented (and with an implementation available to the public in 341 | source code form), and must require no special password or key for 342 | unpacking, reading or copying. 343 | 344 | #### 7. Additional Terms. 345 | 346 | "Additional permissions" are terms that supplement the terms of this 347 | License by making exceptions from one or more of its conditions. 348 | Additional permissions that are applicable to the entire Program shall 349 | be treated as though they were included in this License, to the extent 350 | that they are valid under applicable law. If additional permissions 351 | apply only to part of the Program, that part may be used separately 352 | under those permissions, but the entire Program remains governed by 353 | this License without regard to the additional permissions. 354 | 355 | When you convey a copy of a covered work, you may at your option 356 | remove any additional permissions from that copy, or from any part of 357 | it. (Additional permissions may be written to require their own 358 | removal in certain cases when you modify the work.) You may place 359 | additional permissions on material, added by you to a covered work, 360 | for which you have or can give appropriate copyright permission. 361 | 362 | Notwithstanding any other provision of this License, for material you 363 | add to a covered work, you may (if authorized by the copyright holders 364 | of that material) supplement the terms of this License with terms: 365 | 366 | - a) Disclaiming warranty or limiting liability differently from the 367 | terms of sections 15 and 16 of this License; or 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 | - c) Prohibiting misrepresentation of the origin of that material, 372 | or requiring that modified versions of such material be marked in 373 | reasonable ways as different from the original version; or 374 | - d) Limiting the use for publicity purposes of names of licensors 375 | or authors of the material; or 376 | - e) Declining to grant rights under trademark law for use of some 377 | trade names, trademarks, or service marks; or 378 | - f) Requiring indemnification of licensors and authors of that 379 | material by anyone who conveys the material (or modified versions 380 | of it) with contractual assumptions of liability to the recipient, 381 | for any liability that these contractual assumptions directly 382 | impose on those licensors and authors. 383 | 384 | All other non-permissive additional terms are considered "further 385 | restrictions" within the meaning of section 10. If the Program as you 386 | received it, or any part of it, contains a notice stating that it is 387 | governed by this License along with a term that is a further 388 | restriction, you may remove that term. If a license document contains 389 | a further restriction but permits relicensing or conveying under this 390 | License, you may add to a covered work material governed by the terms 391 | of that license document, provided that the further restriction does 392 | not survive such relicensing or conveying. 393 | 394 | If you add terms to a covered work in accord with this section, you 395 | must place, in the relevant source files, a statement of the 396 | additional terms that apply to those files, or a notice indicating 397 | where to find the applicable terms. 398 | 399 | Additional terms, permissive or non-permissive, may be stated in the 400 | form of a separately written license, or stated as exceptions; the 401 | above requirements apply either way. 402 | 403 | #### 8. Termination. 404 | 405 | You may not propagate or modify a covered work except as expressly 406 | provided under this License. Any attempt otherwise to propagate or 407 | modify it is void, and will automatically terminate your rights under 408 | this License (including any patent licenses granted under the third 409 | paragraph of section 11). 410 | 411 | However, if you cease all violation of this License, then your license 412 | from a particular copyright holder is reinstated (a) provisionally, 413 | unless and until the copyright holder explicitly and finally 414 | terminates your license, and (b) permanently, if the copyright holder 415 | fails to notify you of the violation by some reasonable means prior to 416 | 60 days after the cessation. 417 | 418 | Moreover, your license from a particular copyright holder is 419 | reinstated permanently if the copyright holder notifies you of the 420 | violation by some reasonable means, this is the first time you have 421 | received notice of violation of this License (for any work) from that 422 | copyright holder, and you cure the violation prior to 30 days after 423 | your receipt of the notice. 424 | 425 | Termination of your rights under this section does not terminate the 426 | licenses of parties who have received copies or rights from you under 427 | this License. If your rights have been terminated and not permanently 428 | reinstated, you do not qualify to receive new licenses for the same 429 | material under section 10. 430 | 431 | #### 9. Acceptance Not Required for Having Copies. 432 | 433 | You are not required to accept this License in order to receive or run 434 | a copy of the Program. Ancillary propagation of a covered work 435 | occurring solely as a consequence of using peer-to-peer transmission 436 | to receive a copy likewise does not require acceptance. However, 437 | nothing other than this License grants you permission to propagate or 438 | modify any covered work. These actions infringe copyright if you do 439 | not accept this License. Therefore, by modifying or propagating a 440 | covered work, you indicate your acceptance of this License to do so. 441 | 442 | #### 10. Automatic Licensing of Downstream Recipients. 443 | 444 | Each time you convey a covered work, the recipient automatically 445 | receives a license from the original licensors, to run, modify and 446 | propagate that work, subject to this License. You are not responsible 447 | for enforcing compliance by third parties with this License. 448 | 449 | An "entity transaction" is a transaction transferring control of an 450 | organization, or substantially all assets of one, or subdividing an 451 | organization, or merging organizations. If propagation of a covered 452 | work results from an entity transaction, each party to that 453 | transaction who receives a copy of the work also receives whatever 454 | licenses to the work the party's predecessor in interest had or could 455 | give under the previous paragraph, plus a right to possession of the 456 | Corresponding Source of the work from the predecessor in interest, if 457 | the predecessor has it or can get it with reasonable efforts. 458 | 459 | You may not impose any further restrictions on the exercise of the 460 | rights granted or affirmed under this License. For example, you may 461 | not impose a license fee, royalty, or other charge for exercise of 462 | rights granted under this License, and you may not initiate litigation 463 | (including a cross-claim or counterclaim in a lawsuit) alleging that 464 | any patent claim is infringed by making, using, selling, offering for 465 | sale, or importing the Program or any portion of it. 466 | 467 | #### 11. Patents. 468 | 469 | A "contributor" is a copyright holder who authorizes use under this 470 | License of the Program or a work on which the Program is based. The 471 | work thus licensed is called the contributor's "contributor version". 472 | 473 | A contributor's "essential patent claims" are all patent claims owned 474 | or controlled by the contributor, whether already acquired or 475 | hereafter acquired, that would be infringed by some manner, permitted 476 | by this License, of making, using, or selling its contributor version, 477 | but do not include claims that would be infringed only as a 478 | consequence of further modification of the contributor version. For 479 | purposes of this definition, "control" includes the right to grant 480 | patent sublicenses in a manner consistent with the requirements of 481 | this License. 482 | 483 | Each contributor grants you a non-exclusive, worldwide, royalty-free 484 | patent license under the contributor's essential patent claims, to 485 | make, use, sell, offer for sale, import and otherwise run, modify and 486 | propagate the contents of its contributor version. 487 | 488 | In the following three paragraphs, a "patent license" is any express 489 | agreement or commitment, however denominated, not to enforce a patent 490 | (such as an express permission to practice a patent or covenant not to 491 | sue for patent infringement). To "grant" such a patent license to a 492 | party means to make such an agreement or commitment not to enforce a 493 | patent against the party. 494 | 495 | If you convey a covered work, knowingly relying on a patent license, 496 | and the Corresponding Source of the work is not available for anyone 497 | to copy, free of charge and under the terms of this License, through a 498 | publicly available network server or other readily accessible means, 499 | then you must either (1) cause the Corresponding Source to be so 500 | available, or (2) arrange to deprive yourself of the benefit of the 501 | patent license for this particular work, or (3) arrange, in a manner 502 | consistent with the requirements of this License, to extend the patent 503 | license to downstream recipients. "Knowingly relying" means you have 504 | actual knowledge that, but for the patent license, your conveying the 505 | covered work in a country, or your recipient's use of the covered work 506 | in a country, would infringe one or more identifiable patents in that 507 | country that you have reason to believe are valid. 508 | 509 | If, pursuant to or in connection with a single transaction or 510 | arrangement, you convey, or propagate by procuring conveyance of, a 511 | covered work, and grant a patent license to some of the parties 512 | receiving the covered work authorizing them to use, propagate, modify 513 | or convey a specific copy of the covered work, then the patent license 514 | you grant is automatically extended to all recipients of the covered 515 | work and works based on it. 516 | 517 | A patent license is "discriminatory" if it does not include within the 518 | scope of its coverage, prohibits the exercise of, or is conditioned on 519 | the non-exercise of one or more of the rights that are specifically 520 | granted under this License. You may not convey a covered work if you 521 | are a party to an arrangement with a third party that is in the 522 | business of distributing software, under which you make payment to the 523 | third party based on the extent of your activity of conveying the 524 | work, and under which the third party grants, to any of the parties 525 | who would receive the covered work from you, a discriminatory patent 526 | license (a) in connection with copies of the covered work conveyed by 527 | you (or copies made from those copies), or (b) primarily for and in 528 | connection with specific products or compilations that contain the 529 | covered work, unless you entered into that arrangement, or that patent 530 | license was granted, prior to 28 March 2007. 531 | 532 | Nothing in this License shall be construed as excluding or limiting 533 | any implied license or other defenses to infringement that may 534 | otherwise be available to you under applicable patent law. 535 | 536 | #### 12. No Surrender of Others' Freedom. 537 | 538 | If conditions are imposed on you (whether by court order, agreement or 539 | otherwise) that contradict the conditions of this License, they do not 540 | excuse you from the conditions of this License. If you cannot convey a 541 | covered work so as to satisfy simultaneously your obligations under 542 | this License and any other pertinent obligations, then as a 543 | consequence you may not convey it at all. For example, if you agree to 544 | terms that obligate you to collect a royalty for further conveying 545 | from those to whom you convey the Program, the only way you could 546 | satisfy both those terms and this License would be to refrain entirely 547 | from conveying the Program. 548 | 549 | #### 13. Use with the GNU Affero General Public License. 550 | 551 | Notwithstanding any other provision of this License, you have 552 | permission to link or combine any covered work with a work licensed 553 | under version 3 of the GNU Affero General Public License into a single 554 | combined work, and to convey the resulting work. The terms of this 555 | License will continue to apply to the part which is the covered work, 556 | but the special requirements of the GNU Affero General Public License, 557 | section 13, concerning interaction through a network will apply to the 558 | combination as such. 559 | 560 | #### 14. Revised Versions of this License. 561 | 562 | The Free Software Foundation may publish revised and/or new versions 563 | of the GNU General Public License from time to time. Such new versions 564 | will be similar in spirit to the present version, but may differ in 565 | detail to address new problems or concerns. 566 | 567 | Each version is given a distinguishing version number. If the Program 568 | specifies that a certain numbered version of the GNU General Public 569 | License "or any later version" applies to it, you have the option of 570 | following the terms and conditions either of that numbered version or 571 | of any later version published by the Free Software Foundation. If the 572 | Program does not specify a version number of the GNU General Public 573 | License, you may choose any version ever published by the Free 574 | Software Foundation. 575 | 576 | If the Program specifies that a proxy can decide which future versions 577 | of the GNU General Public License can be used, that proxy's public 578 | statement of acceptance of a version permanently authorizes you to 579 | choose that version for the Program. 580 | 581 | Later license versions may give you additional or different 582 | permissions. However, no additional obligations are imposed on any 583 | author or copyright holder as a result of your choosing to follow a 584 | later version. 585 | 586 | #### 15. Disclaimer of Warranty. 587 | 588 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 589 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 590 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT 591 | WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT 592 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 593 | A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND 594 | PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE 595 | DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR 596 | CORRECTION. 597 | 598 | #### 16. Limitation of Liability. 599 | 600 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 601 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR 602 | CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 603 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES 604 | ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT 605 | NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR 606 | LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM 607 | TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER 608 | PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 609 | 610 | #### 17. Interpretation of Sections 15 and 16. 611 | 612 | If the disclaimer of warranty and limitation of liability provided 613 | above cannot be given local legal effect according to their terms, 614 | reviewing courts shall apply local law that most closely approximates 615 | an absolute waiver of all civil liability in connection with the 616 | Program, unless a warranty or assumption of liability accompanies a 617 | copy of the Program in return for a fee. 618 | 619 | END OF TERMS AND CONDITIONS 620 | 621 | ### How to Apply These Terms to Your New Programs 622 | 623 | If you develop a new program, and you want it to be of the greatest 624 | possible use to the public, the best way to achieve this is to make it 625 | free software which everyone can redistribute and change under these 626 | terms. 627 | 628 | To do so, attach the following notices to the program. It is safest to 629 | attach them to the start of each source file to most effectively state 630 | the exclusion of warranty; and each file should have at least the 631 | "copyright" line and a pointer to where the full notice is found. 632 | 633 | 634 | Copyright (C) 635 | 636 | This program is free software: you can redistribute it and/or modify 637 | it under the terms of the GNU General Public License as published by 638 | the Free Software Foundation, either version 3 of the License, or 639 | (at your option) any later version. 640 | 641 | This program is distributed in the hope that it will be useful, 642 | but WITHOUT ANY WARRANTY; without even the implied warranty of 643 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 644 | GNU General Public License for more details. 645 | 646 | You should have received a copy of the GNU General Public License 647 | along with this program. If not, see . 648 | 649 | Also add information on how to contact you by electronic and paper 650 | 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 661 | appropriate parts of the General Public License. Of course, your 662 | program's commands might be different; for a GUI interface, you would 663 | use an "about box". 664 | 665 | You should also get your employer (if you work as a programmer) or 666 | school, if any, to sign a "copyright disclaimer" for the program, if 667 | necessary. For more information on this, and how to apply and follow 668 | the GNU GPL, see . 669 | 670 | The GNU General Public License does not permit incorporating your 671 | program into proprietary programs. If your program is a subroutine 672 | library, you may consider it more useful to permit linking proprietary 673 | applications with the library. If this is what you want to do, use the 674 | GNU Lesser General Public License instead of this License. But first, 675 | please read . -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pykdclient 2 | 3 | See issue #1 4 | -------------------------------------------------------------------------------- /windpl.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # win/xbox KD client 3 | # 4 | # Copyright (C) 2007 SecureWorks, Inc. 5 | # Copyright (C) 2013 espes 6 | # Copyright (C) 2017 Jannik Vogel 7 | # 8 | # This program is free software subject to the terms of the GNU General 9 | # Public License. You can use, copy, redistribute and/or modify the 10 | # program under the terms of the GNU General Public License as published 11 | # by the Free Software Foundation; either version 3 of the License, or 12 | # (at your option) any later version. You should have received a copy of 13 | # the GNU General Public License along with this program. If not, 14 | # please see http://www.gnu.org/licenses/ for a copy of the GNU General 15 | # Public License. 16 | # 17 | # The program is subject to a disclaimer of warranty and a limitation of 18 | # liability, as disclosed below. 19 | # 20 | # Disclaimer of Warranty. 21 | # 22 | # THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 23 | # APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 24 | # HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT 25 | # WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT 26 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 27 | # PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE 28 | # OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU 29 | # ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, CORRECTION OR 30 | # RECOVERY FROM DATA LOSS OR DATA ERRORS. 31 | # 32 | # Limitation of Liability. 33 | # 34 | # IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 35 | # WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR 36 | # CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 37 | # INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES 38 | # ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT 39 | # NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES 40 | # SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE 41 | # WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN 42 | # ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 43 | 44 | #use IO::Select 45 | #use IO::Socket 46 | #use File::stat 47 | #use Fcntl ':mode' 48 | #use strict 49 | 50 | import socket 51 | import sys 52 | import struct 53 | 54 | dev = sys.argv[1] 55 | timeout = 10 # max time to wait on packet 56 | running = 1 57 | 58 | kernelcontext = {} 59 | kernelcontext['peb'] = 0 60 | kernelcontext['pid'] = 0 61 | kernelcontext['eprocess'] = 0 62 | kernelcontext['dtb'] = 0 63 | 64 | processcontext = {} 65 | processcontext['peb'] = 0 66 | processcontext['pid'] = 0 67 | processcontext['eprocess'] = 0 68 | processcontext['dtb'] = 0 69 | 70 | pcontext = kernelcontext 71 | 72 | #version 73 | #kernelbase 74 | 75 | nextpid = 1 76 | 77 | breakpoints = {} 78 | 79 | curbp = 1 80 | controlspace = 0 81 | controlspacesent = False 82 | 83 | #isserial 84 | #serial 85 | #client 86 | 87 | if False: 88 | ds = stat(dev) or die("$!") 89 | if (S_ISCHR(ds.mode)): 90 | #require Device::SerialPort 91 | #FIXME: serial = tie( *FH, 'Device::SerialPort', "dev" ) or die("Can't tie: $!" 92 | serial.baudrate(115200) 93 | serial.parity("none") 94 | serial.databits(8) 95 | serial.stopbits(1) 96 | serial.handshake("none") 97 | serial.write_settings or die("failed writing settings") 98 | FH.blocking(0) 99 | elif (S_ISSOCK(ds.mode)): 100 | client = None #FIXME: IO::Socket::UNIX->new(Type = SOCK_STREAM, Peer = dev) or die("Can't create socket!") 101 | else: 102 | die("dev not a character device or a socket") 103 | 104 | #FIXME: Add support for TCP sockets too 105 | client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) 106 | print("Connecting to '" + dev + "'") 107 | client.connect(dev) 108 | 109 | def substr(buf, start, length = None): 110 | if length == None: 111 | return buf[start:] 112 | return buf[start:start + length] 113 | 114 | def patch_substr(buf, start, length, fmt, data = None): 115 | if data == None: 116 | data = fmt 117 | return buf[0:start] + fmt + buf[start+length:] 118 | else: 119 | return buf[0:start] + struct.pack(fmt, data) + buf[start+length:] 120 | 121 | def unpack(fmt, data): 122 | return struct.unpack(fmt, data)[0] 123 | 124 | def pack(fmt, data): 125 | return struct.pack(fmt, data) 126 | 127 | def writeDev(data): 128 | if False: 129 | if (serial): 130 | serial.write(data) 131 | else: 132 | client.syswrite(data) 133 | client.send(data) 134 | 135 | def readLoop(wanted): 136 | total = 0 137 | outbuf = bytearray([]) 138 | while ( total < wanted ): 139 | if False: 140 | if (serial): 141 | (count, buf ) = serial.read(1) 142 | else: 143 | #FH.blocking(1) 144 | count = client.sysread(buf, 1) 145 | if (count == 0): 146 | die("eof") 147 | # print("readLoop count %x\n", ord(buf) 148 | #FH.blocking(0) 149 | buf = client.recv(1) 150 | count = len(buf) 151 | if (count): 152 | total += count 153 | outbuf += buf 154 | return outbuf 155 | 156 | def hexformat(buf): 157 | length = len(buf) 158 | if length == 0: 159 | return 160 | b = "0000 " 161 | c = 0 162 | for x in buf: 163 | c += 1 164 | b += "%02x " % x 165 | if ( c % 16 ) == 0: 166 | if ( c < length ): 167 | b += "\n%04x " % c 168 | if substr( b, -1, 1 ) != "\n": 169 | b += "\n" 170 | return b 171 | 172 | #FIXME: Verify behaviour 173 | def cksum(buf): 174 | v = 0 175 | for b in buf: 176 | v += b 177 | return v 178 | 179 | PACKET_LEADER = 0x30303030 180 | CONTROL_PACKET_LEADER = 0x69696969 181 | 182 | PACKET_TYPE_UNUSED = 0 183 | PACKET_TYPE_KD_STATE_CHANGE32 = 1 184 | PACKET_TYPE_KD_STATE_MANIPULATE = 2 185 | PACKET_TYPE_KD_DEBUG_IO = 3 186 | PACKET_TYPE_KD_ACKNOWLEDGE = 4 187 | PACKET_TYPE_KD_RESEND = 5 188 | PACKET_TYPE_KD_RESET = 6 189 | PACKET_TYPE_KD_STATE_CHANGE64 = 7 190 | PACKET_TYPE_MAX = 8 191 | 192 | def handlePacket(): 193 | 194 | ptype, buf = getPacket() 195 | 196 | if (len(buf) == 0): 197 | return 198 | 199 | if (ptype == PACKET_TYPE_KD_STATE_MANIPULATE): 200 | handleStateManipulate(buf) 201 | elif (ptype == PACKET_TYPE_KD_DEBUG_IO): 202 | handleDebugIO(buf) 203 | elif (ptype == PACKET_TYPE_KD_STATE_CHANGE64): 204 | handleStateChange(buf) 205 | 206 | return (ptype, buf) 207 | 208 | def getPacket(): 209 | global nextpid 210 | ptype = None 211 | payload = bytearray([]) 212 | buf = readLoop(4) 213 | plh = unpack( "I", buf ) 214 | if ((plh == PACKET_LEADER) or (plh == CONTROL_PACKET_LEADER)): 215 | print("Got packet leader: %08x" % plh) 216 | 217 | buf = readLoop(2) 218 | ptype = unpack( "H", buf ) 219 | print("Packet type: " + str(ptype) + "") 220 | 221 | buf = readLoop(2) 222 | bc = unpack( "H", buf ) 223 | print("Byte count: " + str(bc) + "") 224 | 225 | buf = readLoop(4) 226 | pid = unpack( "I", buf ) 227 | nextpid = pid 228 | print("Packet ID: %08x" % pid) 229 | 230 | buf = readLoop(4) 231 | ck = unpack( "I", buf ) 232 | print("Checksum: %08x" % ck) 233 | 234 | if bc: 235 | payload = readLoop(bc) 236 | 237 | # send ack if it's a non-control packet 238 | if ( plh == PACKET_LEADER ): 239 | # packet trailer 240 | trail = readLoop(1) 241 | print(hexformat(trail)) 242 | if ( trail[0] == 0xAA ): 243 | # print("sending Ack\n";#) 244 | sendAck() 245 | return (ptype, payload) 246 | 247 | # PACKET_TYPE_KD_DEBUG_IO apis 248 | # DBGKD_DEBUG_IO 249 | DbgKdPrintStringApi = 0x00003230 250 | DbgKdGetStringApi = 0x00003231 251 | def handleDebugIO(buf): 252 | 253 | apiNumber = unpack("I", substr(buf, 0, 4)) 254 | if (apiNumber == DbgKdPrintStringApi): 255 | print("DBG PRINT STRING: " + substr(buf, 0x10).decode('utf-8')) 256 | 257 | # PACKET_TYPE_KD_STATE_CHANGE states 258 | # X86_NT5_DBGKD_WAIT_STATE_CHANGE64 259 | DbgKdExceptionStateChange = 0x00003030 260 | DbgKdLoadSymbolsStateChange = 0x00003031 261 | 262 | def handleStateChange(buf): 263 | 264 | newState = unpack("I", substr(buf, 0, 4)) 265 | print("State Change: %08x" % newState) 266 | 267 | if (newState == DbgKdExceptionStateChange): 268 | exceptions[0xc0000005] = "EXCEPTION_ACCESS_VIOLATION", 269 | exceptions[0xc000008c] = "EXCEPTION_ARRAY_BOUNDS_EXCEEDED", 270 | exceptions[0x80000003] = "EXCEPTION_BREAKPOINT", 271 | exceptions[0x80000002] = "EXCEPTION_DATATYPE_MISALIGNMENT", 272 | exceptions[0xc000008d] = "EXCEPTION_FLT_DENORMAL_OPERAND", 273 | exceptions[0xc000008e] = "EXCEPTION_FLT_DIVIDE_BY_ZERO", 274 | exceptions[0xc000008f] = "EXCEPTION_FLT_INEXACT_RESULT", 275 | exceptions[0xc0000030] = "EXCEPTION_FLT_INVALID_OPERATION", 276 | exceptions[0xc0000091] = "EXCEPTION_FLT_OVERFLOW", 277 | exceptions[0xc0000032] = "EXCEPTION_FLT_STACK_CHECK", 278 | exceptions[0xc0000033] = "EXCEPTION_FLT_UNDERFLOW", 279 | exceptions[0x80000001] = "EXCEPTION_GUARD_PAGE", 280 | exceptions[0xc000001d] = "EXCEPTION_ILLEGAL_INSTRUCTION", 281 | exceptions[0xc0000006] = "EXCEPTION_IN_PAGE_ERROR", 282 | exceptions[0xc0000094] = "EXCEPTION_INT_DIVIDE_BY_ZERO", 283 | exceptions[0xc0000035] = "EXCEPTION_INT_OVERFLOW", 284 | exceptions[0xc00000fd] = "EXCEPTION_STACK_OVERFLOW" 285 | 286 | # DBGKM_EXCEPTION64 287 | ex = substr(buf, 32) 288 | 289 | code = unpack("I", substr(ex,0,4)) 290 | flags = unpack("I", substr(ex,4,4)) 291 | record = unpack("I", substr(ex,8,4)) 292 | address = unpack("I", substr(ex,16,4)) 293 | parameters = unpack("I", substr(ex,24,4)) 294 | 295 | if (code in exceptions): 296 | print("*** %s ", exceptions[code]) 297 | else: 298 | print("*** Exception %08x " % code) 299 | print("at %08x\n", address) 300 | 301 | print("Exception flags = %08x" % flags) 302 | print("Exception record = %08x" % record) 303 | print("Exception address = %08x" % address) 304 | print("Number parameters = %08x" % parameters) 305 | 306 | running = 0 307 | 308 | # my @v = getVersionInfo() 309 | # version = v[0] 310 | # $kernelbase = v[2] 311 | elif (newState == DbgKdLoadSymbolsStateChange): 312 | #DBGKD_LOAD_SYMBOLS64 313 | 314 | filename = substr(buf, 0x3b8) 315 | filename = filename.decode('utf-8').strip() 316 | print("Load Symbols for " + filename + "") 317 | 318 | #nothing to do... 319 | 320 | sendDbgKdContinue2() 321 | 322 | 323 | # PACKET_TYPE_KD_STATE_MANIPULATE api numbers 324 | # DBGKD_MANIPULATE_STATE64 325 | DbgKdReadVirtualMemoryApi = 0x00003130 326 | DbgKdWriteVirtualMemoryApi = 0x00003131 327 | DbgKdGetContextApi = 0x00003132 328 | DbgKdSetContextApi = 0x00003133 329 | DbgKdWriteBreakPointApi = 0x00003134 330 | DbgKdRestoreBreakPointApi = 0x00003135 331 | DbgKdContinueApi = 0x00003136 332 | DbgKdReadControlSpaceApi = 0x00003137 333 | DbgKdWriteControlSpaceApi = 0x00003138 334 | DbgKdReadIoSpaceApi = 0x00003139 335 | DbgKdWriteIoSpaceApi = 0x0000313A 336 | DbgKdRebootApi = 0x0000313B 337 | DbgKdContinueApi2 = 0x0000313C 338 | DbgKdReadPhysicalMemoryApi = 0x0000313D 339 | DbgKdWritePhysicalMemoryApi = 0x0000313E 340 | DbgKdSetSpecialCallApi = 0x00003140 341 | DbgKdClearSpecialCallsApi = 0x00003141 342 | DbgKdSetInternalBreakPointApi = 0x00003142 343 | DbgKdGetInternalBreakPointApi = 0x00003143 344 | DbgKdReadIoSpaceExtendedApi = 0x00003144 345 | DbgKdWriteIoSpaceExtendedApi = 0x00003145 346 | DbgKdGetVersionApi = 0x00003146 347 | DbgKdWriteBreakPointExApi = 0x00003147 348 | DbgKdRestoreBreakPointExApi = 0x00003148 349 | DbgKdCauseBugCheckApi = 0x00003149 350 | DbgKdSwitchProcessor = 0x00003150 351 | DbgKdPageInApi = 0x00003151 352 | DbgKdReadMachineSpecificRegister = 0x00003152 353 | DbgKdWriteMachineSpecificRegister = 0x00003153 354 | DbgKdSearchMemoryApi = 0x00003156 355 | DbgKdGetBusDataApi = 0x00003157 356 | DbgKdSetBusDataApi = 0x00003158 357 | DbgKdCheckLowMemoryApi = 0x00003159 358 | 359 | def handleStateManipulate(buf): 360 | 361 | apiNumber = unpack("I", substr(buf, 0, 4)) 362 | print("State Manipulate: %08x" % apiNumber) 363 | 364 | if ( apiNumber == DbgKdWriteBreakPointApi ): 365 | bp = "%08x" % unpack( "I", substr( buf, 16, 4 ) ) 366 | handle = unpack( "I", substr( buf, 20, 4 ) ) 367 | print("Breakpoint " + handle + " set at " + bp + "") 368 | breakpoints[bp] = handle 369 | elif ( apiNumber == DbgKdRestoreBreakPointApi ): 370 | handle = unpack( "I", substr( buf, 16, 4 ) ) 371 | print("Breakpoint " + handle + " cleared") 372 | elif ( apiNumber == DbgKdGetVersionApi ): 373 | version = substr( buf, 16 ) 374 | print("VERS: " + hexformat(version)) 375 | elif ( apiNumber == DbgKdReadVirtualMemoryApi ): 376 | vmem = substr( buf, 56 ) 377 | print("VMEM:\n" + hexasc(vmem)) 378 | elif ( apiNumber == DbgKdReadPhysicalMemoryApi ): 379 | pmem = substr( buf, 56 ) 380 | print("PMEM:\n" + hexasc(pmem)) 381 | elif ( apiNumber == DbgKdReadControlSpaceApi ): 382 | controlspace = substr( buf, 56 ) 383 | print("CNTL: " + hexformat(controlspace)) 384 | else: 385 | print("UNKN: " + hexasc(buf)) 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | def packetHeader(d): 397 | header = "\x30\x30\x30\x30".encode('utf-8') # packet leader 398 | header += "\x02\x00".encode('utf-8') # packet type PACKET_TYPE_KD_STATE_MANIPULATE 399 | header += pack( "H", len(d) ) # sizeof data 400 | header += pack( "I", nextpid ) # packet id 401 | header += pack( "I", cksum(d) ) # checksum of data 402 | return header 403 | 404 | def sendAck(): 405 | ack = "\x69\x69\x69\x69\x04\x00\x00\x00\x00\x00\x80\x80\x00\x00\x00\x00".encode('utf-8') 406 | print(nextpid) 407 | ack = patch_substr( ack, 8, 4 , "I", nextpid ) 408 | 409 | print(hexformat(ack)) 410 | writeDev(ack) 411 | 412 | def sendReset(): 413 | rst = "\x69\x69\x69\x69\x06\x00\x00\x00\x00\x00\x80\x80\x00\x00\x00\x00".encode('utf-8') 414 | 415 | # print("Sending reset packet\n" 416 | # print(hexformat(rst) 417 | writeDev(rst) 418 | 419 | 420 | def getContext(): 421 | context = {} 422 | sendDbgKdGetContext() 423 | buf = waitStateManipulate(DbgKdGetContextApi) 424 | if ( len(buf) > 204 ): 425 | ctx = substr( buf, 56 ) 426 | 427 | #print("CTXT: ", hexformat($context) 428 | context['ContextFlags'] = unpack( "I", substr( ctx, 0, 4 ) ) 429 | context['DR0'] = unpack( "I", substr( ctx, 4, 4 ) ) 430 | context['DR1'] = unpack( "I", substr( ctx, 8, 4 ) ) 431 | context['DR2'] = unpack( "I", substr( ctx, 12, 4 ) ) 432 | context['DR3'] = unpack( "I", substr( ctx, 16, 4 ) ) 433 | context['DR6'] = unpack( "I", substr( ctx, 20, 4 ) ) 434 | context['DR7'] = unpack( "I", substr( ctx, 24, 4 ) ) 435 | context['fp.ControlWord'] = unpack( "I", substr( ctx, 28, 4 ) ) 436 | context['fp.StatusWord'] = unpack( "I", substr( ctx, 32, 4 ) ) 437 | context['fp.TagWord'] = unpack( "I", substr( ctx, 36, 4 ) ) 438 | context['fp.ErrorOffset'] = unpack( "I", substr( ctx, 40, 4 ) ) 439 | context['fp.ErrorSelector'] = unpack( "I", substr( ctx, 44, 4 ) ) 440 | context['fp.DataOffset'] = unpack( "I", substr( ctx, 48, 4 ) ) 441 | context['fp.DataSelector'] = unpack( "I", substr( ctx, 52, 4 ) ) 442 | context['fp.RegisterArea'] = substr( ctx, 56, 80 ) 443 | context['fp.Cr0NpxState'] = unpack( "I", substr( ctx, 136, 4 ) ) 444 | context['GS'] = unpack( "I", substr( ctx, 140, 4 ) ) 445 | context['FS'] = unpack( "I", substr( ctx, 144, 4 ) ) 446 | context['ES'] = unpack( "I", substr( ctx, 148, 4 ) ) 447 | context['DS'] = unpack( "I", substr( ctx, 152, 4 ) ) 448 | context['EDI'] = unpack( "I", substr( ctx, 156, 4 ) ) 449 | context['ESI'] = unpack( "I", substr( ctx, 160, 4 ) ) 450 | context['EBX'] = unpack( "I", substr( ctx, 164, 4 ) ) 451 | context['EDX'] = unpack( "I", substr( ctx, 168, 4 ) ) 452 | context['ECX'] = unpack( "I", substr( ctx, 172, 4 ) ) 453 | context['EAX'] = unpack( "I", substr( ctx, 176, 4 ) ) 454 | context['EBP'] = unpack( "I", substr( ctx, 180, 4 ) ) 455 | context['EIP'] = unpack( "I", substr( ctx, 184, 4 ) ) 456 | context['CS'] = unpack( "I", substr( ctx, 188, 4 ) ) 457 | context['Eflags'] = unpack( "I", substr( ctx, 192, 4 ) ) 458 | context['ESP'] = unpack( "I", substr( ctx, 196, 4 ) ) 459 | context['SS'] = unpack( "I", substr( ctx, 200, 4 ) ) 460 | context['leftovers'] = substr( ctx, 204 ) 461 | return context 462 | 463 | def setContext(context): 464 | ctx = pack( "I", context['ContextFlags'] ) 465 | ctx += pack( "I", context['DR0'] ) 466 | ctx += pack( "I", context['DR1'] ) 467 | ctx += pack( "I", context['DR2'] ) 468 | ctx += pack( "I", context['DR3'] ) 469 | ctx += pack( "I", context['DR6'] ) 470 | ctx += pack( "I", context['DR7'] ) 471 | ctx += pack( "I", context['fp.ControlWord'] ) 472 | ctx += pack( "I", context['fp.StatusWord'] ) 473 | ctx += pack( "I", context['fp.TagWord'] ) 474 | ctx += pack( "I", context['fp.ErrorOffset'] ) 475 | ctx += pack( "I", context['fp.ErrorSelector'] ) 476 | ctx += pack( "I", context['fp.DataOffset'] ) 477 | ctx += pack( "I", context['fp.DataSelector'] ) 478 | ctx += context['fp.RegisterArea'] 479 | ctx += pack( "I", context['fp.Cr0NpxState'] ) 480 | ctx += pack( "I", context['GS'] ) 481 | ctx += pack( "I", context['FS'] ) 482 | ctx += pack( "I", context['ES'] ) 483 | ctx += pack( "I", context['DS'] ) 484 | ctx += pack( "I", context['EDI'] ) 485 | ctx += pack( "I", context['ESI'] ) 486 | ctx += pack( "I", context['EBX'] ) 487 | ctx += pack( "I", context['EDX'] ) 488 | ctx += pack( "I", context['ECX'] ) 489 | ctx += pack( "I", context['EAX'] ) 490 | ctx += pack( "I", context['EBP'] ) 491 | ctx += pack( "I", context['EIP'] ) 492 | ctx += pack( "I", context['CS'] ) 493 | ctx += pack( "I", context['Eflags'] ) 494 | ctx += pack( "I", context['ESP'] ) 495 | ctx += pack( "I", context['SS'] ) 496 | ctx += context['leftovers'] 497 | sendDbgKdSetContext(ctx) 498 | waitStateManipulate(DbgKdSetContextApi) 499 | 500 | def getVersionInfo(): 501 | print("getVersionInfo") 502 | # os version, protocol version, kernel base, module list, debugger data 503 | sendDbgKdGetVersion() 504 | buf = waitStateManipulate(DbgKdGetVersionApi) 505 | if ( len(buf) > 32 ): 506 | v = substr( buf, 16 ) 507 | osv = "%d.%d" % (unpack( "H", substr( v, 4, 2 ) ), unpack( "H", substr( v, 6, 2 ) )) 508 | pv = unpack( "H", substr( v, 8, 2 ) ) 509 | machinetype = unpack( "H", substr( v, 12, 2 ) ) 510 | kernbase = unpack( "I", substr( v, 16, 4 ) ) 511 | modlist = unpack( "I", substr( v, 24, 4 ) ) 512 | ddata = unpack( "I", substr( v, 32, 4 ) ) 513 | if ( pv < 5 ): 514 | print("Debug protocol version %d not supported" % pv) 515 | sys.exit() 516 | if ( machinetype and ( machinetype != 0x2d ) ): 517 | print("Processor architecture %04x not supported" % machinetype) 518 | sys.exit() 519 | 520 | print("Windows version = %s" % osv) 521 | print("Protocol version = %d" % pv) 522 | print("Kernel base = %08x" % kernbase) 523 | print("Module list = %08x" % modlist) 524 | print("Debugger data = %08x" % ddata) 525 | 526 | return ( osv, pv, kernbase, modlist, ddata ) 527 | return ( "0.0", 0, 0, 0, 0 ) 528 | 529 | def printVersionData(): 530 | v = getVersionInfo() 531 | print("Windows version = %s" % v[0]) 532 | print("Protocol version = %d" % v[1]) 533 | print("Kernel base = %08x" % v[2]) 534 | print("Module list = %08x" % v[3]) 535 | print("Debugger data = %08x" % v[4]) 536 | 537 | if False: 538 | def getKernelModules(): 539 | save = pcontext 540 | pcontext = kernelcontext # this procedure is kernel context only 541 | modules = [] 542 | v = getVersionInfo() 543 | flink = readDword( v[3] ) 544 | modlist = walkList(flink) 545 | for mod in modlist: 546 | 547 | #print("module at %08x\n", $mod 548 | buf = readVirtualMemory( mod, 0x34 ) 549 | if ( len(buf) == 0x34 ): 550 | base = unpack( "I", substr( buf, 0x18, 4 ) ) 551 | if base == 0: 552 | continue 553 | entry = unpack( "I", substr( buf, 0x1c, 4 ) ) 554 | size = unpack( "I", substr( buf, 0x20, 4 ) ) 555 | path = substr( buf, 0x24, 8 ) 556 | name = substr( buf, 0x2c, 8 ) 557 | modules[base]['name'] = unicodeStructToAscii(name) 558 | modules[base]['path'] = unicodeStructToAscii(path) 559 | modules[base]['size'] = size 560 | modules[base]['entry'] = entry 561 | pcontext = save 562 | return modules 563 | 564 | def unicodeStructToAscii(struct): 565 | if len(struct) != 8: 566 | return 567 | length = unpack( "H", substr( struct, 0, 2 ) ) 568 | vaddr = unpack( "I", substr( struct, 4, 4 ) ) 569 | buf = readVirtualMemory( vaddr, length ) 570 | if ( len(buf) == length ): 571 | buf = None #FIXME: =~ s/\x00//g; # ok not really Unicode to Ascii 572 | return buf 573 | 574 | def hexasc(buf): 575 | length = len(buf) 576 | if length == 0: 577 | return 578 | count = 0 579 | ascii = "" 580 | out = "0000 " 581 | for x in buf: 582 | c = ord(x) 583 | out += "%02x " % c 584 | if ( ( c > 0x1f ) and ( c < 0x7f ) ): 585 | ascii += x 586 | else: 587 | ascii += "." 588 | count += 1 589 | if ( count % 16 ) == 0: 590 | if ( count < length ): 591 | out += " " + ascii + "\n%04x " % count 592 | else: 593 | out += " " + ascii + "\n" 594 | ascii = "" 595 | if (ascii): 596 | padding = 48 - ( ( count % 16 ) * 3 ) 597 | out += " " * padding 598 | out += " " + ascii + "\n" 599 | return out 600 | 601 | def sendManipulateStatePacket(d): 602 | h = packetHeader(d) 603 | 604 | print("SEND: " + hexformat(h) + hexformat(d)) 605 | writeDev(h) 606 | writeDev(d) 607 | writeDev(bytes([0xAA])) 608 | 609 | def sendDbgKdContinue2(): 610 | 611 | #print("Sending DbgKdContinue2Api packet\n" 612 | d = bytearray([0] * 56) 613 | d = patch_substr( d, 0, 4 , "I", DbgKdContinueApi2 ) 614 | d = patch_substr( d, 8, 4 , "I", 0x00010001 ) 615 | d = patch_substr( d, 16, 4 , "I", 0x00010001 ) 616 | d = patch_substr( d, 24, 4 , "I", 0x400 ) # TraceFlag 617 | d = patch_substr( d, 28, 4 , "I", 0x01 ) # Dr7 618 | sendManipulateStatePacket(d) 619 | 620 | def sendDbgKdGetVersion(): 621 | 622 | #print("Sending DbgKdGetVersionApi packet\n" 623 | d = bytearray([0] * 56) 624 | d = patch_substr( d, 0, 4 , "I", DbgKdGetVersionApi ) 625 | sendManipulateStatePacket(d) 626 | 627 | def sendDbgKdWriteBreakPoint(bp): 628 | bp = hex(bp) 629 | 630 | #print("Sending DbgKdWriteBreakPointApi packet\n" 631 | d = bytearray([0] * 56) 632 | d = patch_substr( d, 0, 4 , "I", DbgKdWriteBreakPointApi ) 633 | d = patch_substr( d, 16, 4 , "I", bp ) 634 | d = patch_substr( d, 20, 4 , "I", curbp ) 635 | curbp += 1 636 | sendManipulateStatePacket(d) 637 | 638 | def sendDbgKdRestoreBreakPoint(bp): 639 | if ( defined( breakpoints[bp] ) ): 640 | 641 | #print("Sending DbgKdRestoreBreakPointApi packet\n" 642 | d = bytearray([0] * 56) 643 | d = patch_substr( d, 0, 4 , "I", DbgKdRestoreBreakPointApi ) 644 | d = patch_substr( d, 16, 4 , "I", breakpoints[bp] ) 645 | sendManipulateStatePacket(d) 646 | delete( breakpoints[bp] ) 647 | else: 648 | print("Breakpoint not set at bp") 649 | 650 | def sendDbgKdReadControlSpace(): 651 | 652 | #print("Sending DbgKdReadControlSpaceApi packet\n" 653 | d = bytearray([0] * 56) 654 | d = patch_substr( d, 0, 4 , "I", 0x3137 ) 655 | d = patch_substr( d, 16, 4 , "I", 0x02cc ) 656 | d = patch_substr( d, 24, 4 , "I", 84 ) 657 | sendManipulateStatePacket(d) 658 | 659 | def sendDbgKdWriteControlSpace(): 660 | 661 | #print("Sending DbgKdWriteControlSpaceApi packet\n" 662 | d = bytearray([0] * 56) 663 | d = patch_substr( d, 0, 4 , "I", 0x3138 ) 664 | d = patch_substr( d, 16, 4 , "I", 0x02cc ) 665 | d = patch_substr( d, 24, 4 , "I", 84 ) 666 | d += controlspace 667 | sendManipulateStatePacket(d) 668 | controlspacesent = 1 669 | 670 | def sendDbgKdGetContext(): 671 | 672 | #print("Sending DbgKdGetContextApi packet\n" 673 | d = bytearray([0] * 56) 674 | d = patch_substr( d, 0, 4 , "I", DbgKdGetContextApi ) 675 | sendManipulateStatePacket(d) 676 | 677 | def sendDbgKdSetContext(ctx): 678 | 679 | #print("Sending DbgKdSetContextApi packet\n" 680 | d = bytearray([0] * 56) 681 | d = patch_substr( d, 0, 4 , "I", DbgKdSetContextApi ) 682 | d = patch_substr( d, 16, 4, substr( ctx, 0, 4 )) 683 | d += ctx 684 | sendManipulateStatePacket(d) 685 | 686 | def sendDbgKdReadPhysicalMemory(addr, readlen): 687 | 688 | #print("Sending DbgKdReadPhysicalMemoryApi packet\n" 689 | d = bytearray([0] * 56) 690 | d = patch_substr( d, 0, 4 , "I", DbgKdReadPhysicalMemoryApi ) 691 | d = patch_substr( d, 16, 4 , "I", addr ) 692 | d = patch_substr( d, 24, 4 , "I", readlen ) 693 | sendManipulateStatePacket(d) 694 | 695 | def sendDbgKdReadVirtualMemory(vaddr, readlen): 696 | 697 | #print("Sending DbgKdReadVirtualMemoryApi packet\n" 698 | d = bytearray([0] * 56) 699 | d = patch_substr( d, 0, 4 , "I", DbgKdReadVirtualMemoryApi ) 700 | d = patch_substr( d, 16, 4 , "I", vaddr ) 701 | d = patch_substr( d, 24, 4 , "I", readlen ) 702 | sendManipulateStatePacket(d) 703 | 704 | def sendDbgKdWriteVirtualMemory(vaddr, data): 705 | writelen = len(data) 706 | 707 | #print("Sending DbgKdWriteVirtualMemoryApi packet\n" 708 | d = bytearray([0] * 56) 709 | d = patch_substr( d, 0, 4 , "I", DbgKdWriteVirtualMemoryApi ) 710 | d = patch_substr( d, 16, 4 , "I", vaddr ) 711 | d = patch_substr( d, 24, 4 , "I", writelen ) 712 | d += data 713 | sendManipulateStatePacket(d) 714 | 715 | def readDword(addr): 716 | 717 | #print("Reading dword at %08x\n", addr 718 | buf = readVirtualMemory( addr, 4 ) 719 | if ( len(buf) == 4 ): 720 | return unpack( "I", buf ) 721 | return "failed" 722 | 723 | def readPhysicalMemory(addr, length): 724 | chunksize = 0x800 # max to request in one packet 725 | out = bytearray([]) 726 | while ( length > 0 ): 727 | 728 | if ( length < chunksize ): 729 | sendDbgKdReadPhysicalMemory( addr, length ) 730 | buf = waitStateManipulate(DbgKdReadPhysicalMemoryApi) 731 | if ( len(buf) > 56 ): 732 | out += substr( buf, 56 ) 733 | length = 0 734 | else: 735 | sendDbgKdReadPhysicalMemory( addr, chunksize ) 736 | buf = waitStateManipulate(DbgKdReadPhysicalMemoryApi) 737 | if ( len(buf) > 56 ): 738 | out += substr( buf, 56 ) 739 | length -= chunksize 740 | addr += chunksize 741 | return out 742 | 743 | def writePhysicalMemory(addr, buf): 744 | length = len(buf) 745 | chunksize = 0x800 # max to send in one packet 746 | offset = 0 747 | #FIXME: Logic sucks here.. 748 | while ( length > 0 ): 749 | if ( length < chunksize ): 750 | sendDbgKdWritePhysicalMemory( addr, buf ) 751 | waitStateManipulate(0x313e) 752 | length = 0 753 | else: 754 | sendDbgKdWritePhysicalMemory( addr, substr( buf, offset, chunksize ) ) 755 | waitStateManipulate(0x313e) 756 | length -= chunksize 757 | offset += chunksize 758 | addr += chunksize 759 | return 760 | 761 | def writeVirtualMemory(addr, buf): 762 | length = len(buf) 763 | #FIXME: return unless addr && length 764 | chunksize = 0x800 # max to send in one packet 765 | offset = 0 766 | if ( pcontext['pid'] == 0 ): 767 | #FIXME: Logic sucks here.. 768 | while ( length > 0 ): 769 | if ( length < chunksize ): 770 | sendDbgKdWriteVirtualMemory( addr, buf ) 771 | waitStateManipulate(DbgKdWriteVirtualMemoryApi) 772 | length = 0 773 | else: 774 | sendDbgKdWriteVirtualMemory( addr, substr( buf, offset, chunksize ) ) 775 | waitStateManipulate(DbgKdWriteVirtualMemoryApi) 776 | length -= chunksize 777 | offset += chunksize 778 | addr += chunksize 779 | else: 780 | distance_to_page_boundary = 0x1000 - ( addr & 0xfff ) 781 | #FIXME: Logic sucks here.. 782 | if ( distance_to_page_boundary > length ): 783 | physaddr = logical2physical(addr) 784 | writePhysicalMemory( physaddr, buf ) 785 | return 786 | else: 787 | physaddr = logical2physical(addr) 788 | buf = writePhysicalMemory( physaddr, substr( buf, 0, distance_to_page_boundary ) ) 789 | addr += distance_to_page_boundary 790 | offset += distance_to_page_boundary 791 | remainder = length - distance_to_page_boundary 792 | 793 | while ( remainder > 0 ): 794 | if ( remainder < 0x1000 ): 795 | physaddr = logical2physical(addr) 796 | writePhysicalMemory( physaddr, substr( buf, offset, remainder ) ) 797 | remainder = 0 798 | else: 799 | physaddr = logical2physical(addr) 800 | writePhysicalMemory( physaddr, substr( buf, offset, 0x1000 ) ) 801 | addr += 0x1000 802 | offset += 0x1000 803 | remainder -= 0x1000 804 | return 805 | 806 | #FIXME: Indentation is horrible 807 | def readVirtualMemory(addr, length): 808 | #FIXME: return unless addr && length 809 | chunksize = 0x800 # max to request in one packet 810 | out = bytearray() 811 | buf = bytearray() 812 | if ( pcontext['pid'] == 0 ): 813 | while ( length > 0 ): 814 | if ( length < chunksize ): 815 | sendDbgKdReadVirtualMemory( addr, length ) 816 | buf = waitStateManipulate(DbgKdReadVirtualMemoryApi) 817 | if ( len(buf) > 56 ): 818 | out += substr( buf, 56 ) 819 | length = 0 820 | else: 821 | sendDbgKdReadVirtualMemory( addr, chunksize ) 822 | buf = waitStateManipulate(DbgKdReadVirtualMemoryApi) 823 | if ( len(buf) > 56 ): 824 | out += substr( buf, 56 ) 825 | length -= chunksize 826 | addr += chunksize 827 | return out 828 | else: 829 | distance_to_page_boundary = 0x1000 - ( addr & 0xfff ) 830 | if ( distance_to_page_boundary > length ): 831 | physaddr = logical2physical(addr) 832 | return readPhysicalMemory( physaddr, length ) 833 | else: 834 | physaddr = logical2physical(addr) 835 | buf = readPhysicalMemory( physaddr, distance_to_page_boundary ) 836 | addr += distance_to_page_boundary 837 | remainder = length - distance_to_page_boundary 838 | while ( remainder > 0 ): 839 | if ( remainder < 0x1000 ): 840 | physaddr = logical2physical(addr) 841 | buf += readPhysicalMemory( physaddr, remainder ) 842 | remainder = 0 843 | else: 844 | physaddr = logical2physical(addr) 845 | buf += readPhysicalMemory( physaddr, 0x1000 ) 846 | addr += 0x1000 847 | remainder -= 0x1000 848 | return buf 849 | 850 | 851 | def sendDbgKdReboot(): 852 | print("Sending DbgKdRebootApi packet") 853 | d = bytearray([0] * 56) 854 | d = patch_substr( d, 0, 4 , "I", 0x313b ) 855 | sendManipulateStatePacket(d) 856 | 857 | 858 | def waitStateManipulate(wanted): 859 | if running: 860 | return 861 | 862 | ptype = bytearray([]) 863 | buf = bytearray([]) 864 | try: 865 | while (1): 866 | (ptype, buf) = handlePacket(1) 867 | if (ptype == PACKET_TYPE_KD_STATE_MANIPULATE): 868 | api = unpack( "I", substr( buf, 0, 4 ) ) 869 | if (api == wanted): 870 | break 871 | except timeout: 872 | print("Timeout waiting for %04x packet reply" % wanted) 873 | return buf 874 | 875 | def getPspCidTable(): 876 | pspcidtable = 0 877 | save = pcontext 878 | pcontext = kernelcontext # this procedure is kernel context only 879 | sendDbgKdGetVersion() 880 | buf = waitStateManipulate(DbgKdGetVersionApi) 881 | pddata = unpack( "I", substr( buf, 48, 4 ) ) 882 | if (pddata): 883 | #print("Pointer to debugger data struct is at %08x\n", pddata 884 | ddata = readDword(pddata) 885 | if ( ddata != "failed" ): 886 | #print("debugger data struct is at %08x\n", ddata 887 | pspcidtable = readDword( ddata + 88 ) 888 | if ( pspcidtable != "failed" ): 889 | #print("PspCidTable is %08x\n", $pspcidtable 890 | pcontext = save 891 | return pspcidtable 892 | pcontext = save 893 | return 0 894 | 895 | 896 | 897 | sendReset() 898 | while(True): 899 | handlePacket() 900 | print("") 901 | 902 | # FIXME: windpl_loop.py 903 | 904 | -------------------------------------------------------------------------------- /windpl_extra.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007 SecureWorks, Inc. 2 | # Copyright (C) 2013 espes 3 | # Copyright (C) 2017 Jannik Vogel 4 | # 5 | # This program is free software subject to the terms of the GNU General 6 | # Public License. You can use, copy, redistribute and/or modify the 7 | # program under the terms of the GNU General Public License as published 8 | # by the Free Software Foundation; either version 3 of the License, or 9 | # (at your option) any later version. You should have received a copy of 10 | # the GNU General Public License along with this program. If not, 11 | # please see http://www.gnu.org/licenses/ for a copy of the GNU General 12 | # Public License. 13 | # 14 | # The program is subject to a disclaimer of warranty and a limitation of 15 | # liability, as disclosed below. 16 | # 17 | # Disclaimer of Warranty. 18 | # 19 | # THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 20 | # APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 21 | # HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT 22 | # WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT 23 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 24 | # PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE 25 | # OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU 26 | # ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, CORRECTION OR 27 | # RECOVERY FROM DATA LOSS OR DATA ERRORS. 28 | # 29 | # Limitation of Liability. 30 | # 31 | # IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 32 | # WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR 33 | # CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 34 | # INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES 35 | # ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT 36 | # NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES 37 | # SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE 38 | # WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN 39 | # ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 40 | 41 | 42 | 43 | def injectSUSShellcode: 44 | title = shift 45 | message = shift 46 | userbase = 0x7ffe0800 47 | ring0base = 0xffdf0800 48 | save = $pcontext 49 | $pcontext = \%kernelcontext; # this procedure is kernel context only 50 | messageboxa = getProcAddress( "user32.dll", "MessageBoxA" ) 51 | 52 | sc = 53 | "\x6a\x00\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\x6A\x00\xE8\x00\x00\x00\x00\xc3$title\x00$message\x00" 54 | substr( $sc, 3, 4 ) = pack( "I", $userbase + 20 ) 55 | substr( $sc, 8, 4 ) = pack( "I", $userbase + 21 + len($title) ) 56 | substr( $sc, 15, 4 ) = pack( "I", $messageboxa - ( $userbase + 19 ) ) 57 | 58 | writeVirtualMemory( $ring0base, $sc ) 59 | printf "Shellcode injected at %08x (%08x)\n", $ring0base, $userbase 60 | $pcontext = $save 61 | 62 | def insertApc: 63 | print "Searching for thread in explorer.exe\n" 64 | my %procs = getProcessList() 65 | thread 66 | for ( sort keys %procs ): 67 | n = lc( $procs{$_}{'name'] ) 68 | print "Found $n\n" 69 | if ( $n == "explorer.exe" ): 70 | 71 | #printf "Found explorer.exe\n" 72 | $thread = shift( @{ $procs{$_}{'threads'] } ) 73 | last 74 | unless ($thread): 75 | print "Failed to find thread\n" 76 | return 77 | printf "Using thread object at %08x\n", $thread 78 | kernelret = findRet() 79 | shellcode = 0x7ffe0800 80 | apc = "\x00" x 48 81 | putme = 0xffdf0900 82 | save = $pcontext 83 | $pcontext = \%kernelcontext; # this procedure is kernel context only 84 | substr( $apc, 0, 2 ) = pack( "S", 0x12 ); # type = Apc object 85 | substr( $apc, 2, 2 ) = pack( "S", 0x30 ); # size of object = 48 bytes 86 | substr( $apc, 8, 4 ) = pack( "I", $thread ); # ethread ptr 87 | substr( $apc, 20, 4 ) = pack( "I", $kernelret ); # ret command in kernel 88 | substr( $apc, 28, 4 ) = pack( "I", $shellcode ); # shellcode vaddr 89 | substr( $apc, 36, 4 ) = pack( "I", $putme + 0x50 ); # system arg 1 90 | substr( $apc, 40, 4 ) = pack( "I", $putme + 0x54 ); # system arg 2 91 | substr( $apc, 46, 1 ) = "\x01"; # Apc mode = user mode 92 | substr( $apc, 47, 1 ) = "\x01"; # Inserted = true (well, it will be) 93 | 94 | printf "Built APC object for thread at %08x\n", $thread 95 | 96 | #print hexformat($apc) 97 | printf "Inserting into APC list at %08x\n", $thread + 0x3c 98 | oldflink = readDword( $thread + 0x3c ) 99 | printf "Replacing old Apc flink: %08x\n", $oldflink 100 | if ( $oldflink != "failed" ): 101 | substr( $apc, 12, 4 ) = pack( "I", $oldflink ); # flink 102 | substr( $apc, 16, 4 ) = pack( "I", $thread + 0x3c ); # blink 103 | 104 | # write APC object to SharedUserSpace 105 | writeVirtualMemory( $putme, $apc ) 106 | 107 | # insert our APC into the list 108 | writeVirtualMemory( $thread + 0x3c, pack( "I", $putme + 12 ) ) 109 | 110 | # set UserApcPending = TRUE 111 | writeVirtualMemory( $thread + 0x4a, "\x01" ) 112 | printf "Inserted APC into thread at %08x\n", $thread 113 | else: 114 | print "Failed to insert APC\n" 115 | $pcontext = $save 116 | 117 | def parsePE: 118 | 119 | # Some PE parsing code borrowed from Metasploit PE module 120 | my %pe_hdr 121 | crap 122 | base = shift 123 | data = readVirtualMemory( $base, 0x800 ) 124 | $data += readVirtualMemory( $base + 0x800, 0x800 ) 125 | 126 | #printf "Read %d bytes of PE header at %08x\n", len($data),$base 127 | return unless len($data) == 0x1000 128 | 129 | return unless substr( $data, 0, 2 ) == "MZ" 130 | peo = unpack( "I", substr( $data, 0x3c, 4 ) ) 131 | return unless substr( $data, $peo, 2 ) == "PE" 132 | 133 | pe_hdr["MachineID"] = unpack( "S", substr( $data, $peo + 4 ) ) 134 | pe_hdr["NumberOfSections"] = unpack( "S", substr( $data, $peo + 6 ) ) 135 | pe_hdr["TimeDateStamp"] = unpack( "L", substr( $data, $peo + 8 ) ) 136 | pe_hdr["PointerToSymbolTable"] = unpack( "L", substr( $data, $peo + 12 ) ) 137 | pe_hdr["NumberOfSymbols"] = unpack( "L", substr( $data, $peo + 16 ) ) 138 | pe_hdr["SizeOfOptionalHeader"] = unpack( "S", substr( $data, $peo + 20 ) ) 139 | pe_hdr["Characteristics"] = unpack( "S", substr( $data, $peo + 22 ) ) 140 | 141 | if ( pe_hdr["SizeOfOptionalHeader"] < 224 ): 142 | return 0 143 | opthdr = substr( $data, $peo + 24, pe_hdr["SizeOfOptionalHeader"] ) 144 | pe_hdr["Magic "] = unpack( "S", substr( $opthdr, 0 ) ) 145 | pe_hdr["MajorLinker"] = unpack( "C", substr( $opthdr, 2 ) ) 146 | pe_hdr["MinorLinker"] = unpack( "C", substr( $opthdr, 3 ) ) 147 | pe_hdr["SizeOfCode"] = unpack( "L", substr( $opthdr, 4 ) ) 148 | pe_hdr["SizeOfInitialized"] = unpack( "L", substr( $opthdr, 8 ) ) 149 | pe_hdr["SizeOfUninitialized"] = unpack( "L", substr( $opthdr, 12 ) ) 150 | 151 | pe_hdr["EntryPoint"] = unpack( "L", substr( $opthdr, 16 ) ) 152 | pe_hdr["BaseOfCode"] = unpack( "L", substr( $opthdr, 20 ) ) 153 | pe_hdr["BaseOfData"] = unpack( "L", substr( $opthdr, 24 ) ) 154 | 155 | pe_hdr["ImageBase"] = unpack( "L", substr( $opthdr, 28 ) ) 156 | pe_hdr["SectionAlign"] = unpack( "L", substr( $opthdr, 32 ) ) 157 | pe_hdr["FileAlign"] = unpack( "L", substr( $opthdr, 36 ) ) 158 | 159 | pe_hdr["MajorOS"] = unpack( "S", substr( $opthdr, 38 ) ) 160 | pe_hdr["MinorOS"] = unpack( "S", substr( $opthdr, 40 ) ) 161 | pe_hdr["MajorImage"] = unpack( "S", substr( $opthdr, 42 ) ) 162 | pe_hdr["MinorImage"] = unpack( "S", substr( $opthdr, 44 ) ) 163 | pe_hdr["MajorSub"] = unpack( "S", substr( $opthdr, 46 ) ) 164 | pe_hdr["MinorSub"] = unpack( "S", substr( $opthdr, 48 ) ) 165 | 166 | pe_hdr["Reserved"] = unpack( "L", substr( $opthdr, 52 ) ) 167 | pe_hdr["SizeOfImage"] = unpack( "L", substr( $opthdr, 56 ) ) 168 | pe_hdr["SizeOfHeaders"] = unpack( "L", substr( $opthdr, 60 ) ) 169 | pe_hdr["Checksum"] = unpack( "L", substr( $opthdr, 64 ) ) 170 | pe_hdr["Subsystem"] = unpack( "S", substr( $opthdr, 68 ) ) 171 | pe_hdr["DllCharacteristics"] = unpack( "S", substr( $opthdr, 70 ) ) 172 | pe_hdr["SizeOfStackReserve"] = unpack( "L", substr( $opthdr, 72 ) ) 173 | pe_hdr["SizeOfStackCommit"] = unpack( "L", substr( $opthdr, 76 ) ) 174 | pe_hdr["SizeOfHeapReserve"] = unpack( "L", substr( $opthdr, 80 ) ) 175 | pe_hdr["SizeOfHeapCommit"] = unpack( "L", substr( $opthdr, 84 ) ) 176 | pe_hdr["LoaderFlags"] = unpack( "L", substr( $opthdr, 88 ) ) 177 | pe_hdr["NumberOfRvaAndSizes"] = unpack( "L", substr( $opthdr, 92 ) ) 178 | 179 | my @RVAMAP = qw(export import resource exception certificate basereloc 180 | debug archspec globalptr tls load_config boundimport importaddress 181 | delayimport comruntime none) 182 | 183 | # parse the rva data 184 | rva_data = substr( $opthdr, 96, pe_hdr["NumberOfRvaAndSizes"] * 8 ) 185 | my %RVA 186 | for x in range(0, pe_hdr{"NumberOfRvaAndSizes"): 187 | if ( !$RVAMAP[$x] ) { $RVAMAP[$x] = "unknown_$x" $RVA{ $RVAMAP[$x] } = [ 188 | unpack( "L", substr( $rva_data, ( $x * 8 ) ) ), 189 | unpack( "L", substr( $rva_data, ( $x * 8 ) + 4 ) ), 190 | ] 191 | 192 | # parse the section headers 193 | sec_begn = $peo + 24 + pe_hdr["SizeOfOptionalHeader"] 194 | sec_data = substr( $data, $sec_begn ) 195 | 196 | for x in range(0, pe_hdr{"NumberOfSections"): 197 | sec_head = $sec_begn + ( $x * 40 ) 198 | sec_name = substr( $data, $sec_head, 8 ) 199 | $sec_name =~ s/\x00//g 200 | if ( $sec_name == "" ) { $sec_name = ".sec$x" 201 | #sec_name = ".sec$x" 202 | vsize = unpack( "L", substr( $data, $sec_head + 8 ) ) 203 | voffset = unpack( "L", substr( $data, $sec_head + 12 ) ) 204 | rsize = unpack( "L", substr( $data, $sec_head + 16 ) ) 205 | roffset = unpack( "L", substr( $data, $sec_head + 20 ) ) 206 | if ( $voffset == pe_hdr["BaseOfCode"] ): 207 | $type = "CODE" 208 | elsif ( $voffset == pe_hdr["BaseOfData"] ): 209 | $type = "DATA" 210 | else: 211 | $type = "UNKNOWN" 212 | pe_hdr['import'] = $RVA{'import']->[0] 213 | pe_hdr['export'] = $RVA{'export']->[0] 214 | pe_hdr['importsize'] = $RVA{'import']->[1] 215 | pe_hdr['exportsize'] = $RVA{'export']->[1] 216 | return %pe_hdr 217 | 218 | def getImports: 219 | base = shift; # base address of module 220 | ioffset = shift; # offset to import table 221 | size = shift; # size of import table 222 | crap 223 | 224 | imports = readVirtualMemory( $base + $ioffset, $size ) 225 | 226 | for ( i = 0 ; $i < $size ; $i += 20 ): 227 | last if substr( $imports, $i, 20 ) == "\x00" x 20 228 | rvaILT = unpack( "L", substr( $imports, $i, 4 ) ) 229 | timestamp = unpack( "L", substr( $imports, $i + 4, 4 ) ) 230 | forwarderchain = unpack( "L", substr( $imports, $i + 8, 4 ) ) 231 | rvaModuleName = unpack( "L", substr( $imports, $i + 12, 4 ) ) 232 | rvaIAT = unpack( "L", substr( $imports, $i + 16, 4 ) ) 233 | modname = readVirtualMemory( $base + $rvaModuleName ) 234 | $modname =~ s/\x00.*// 235 | 236 | if ($rvaILT): 237 | count = 0 238 | ibuf = readVirtualMemory( $base + $rvaILT, 4 ) 239 | IGRAB: while ( $ibuf != "\x00\x00\x00\x00" ): 240 | importthunkRVA = unpack( "L", $ibuf ) 241 | last IGRAB if $importthunkRVA == 0 242 | 243 | if ( $importthunkRVA & 0x8000000 ): 244 | printf "ORD: 0x%x\n", $importthunkRVA & ~0x80000000 245 | else: 246 | importname = 247 | readVirtualMemory( $importthunkRVA & ~0x80000000, 255 ) 248 | $importname = substr( $importname, 2 ) 249 | ( $importname, $crap ) = split( /\x00/, $importname ) 250 | thunk = $base + $rvaIAT + ( $count * 4 ) 251 | my ( $mod, $suff ) = split( /\./, lc($modname) ) 252 | printf "%s (0x%x)\n", $importname, $thunk 253 | $count++ 254 | $ibuf = 255 | readVirtualMemory( $base + ( $rvaILT + $count * 4 ), 4 ) 256 | } # end while 257 | } # end if rvaILT 258 | else: 259 | count = 0 260 | ibuf = readVirtualMemory( $base + $rvaIAT, 4 ) 261 | IGRAB: while ( $ibuf != "\x00\x00\x00\x00" ): 262 | importthunkRVA = unpack( "L", $ibuf ) 263 | last IGRAB if $importthunkRVA == 0 264 | importname = 265 | readVirtualMemory( $base + $importthunkRVA, 255 ) 266 | $importname = substr( $importname, 2 ) 267 | ( $importname, $crap ) = split( /\x00/, $importname ) 268 | thunk = $base + $rvaIAT + ( $count * 4 ) 269 | my ( $mod, $suff ) = split( /\./, lc($modname) ) 270 | printf "%s (0x%x)\n", $importname, $thunk 271 | 272 | $count++ 273 | $ibuf = readVirtualMemory( $base + $rvaIAT, 4 ) 274 | } # end while 275 | } # end if rvaILT 276 | } # end if import module 277 | 278 | def locateExportNameInTable: 279 | procname = shift 280 | base = shift 281 | eoffset = shift 282 | size = shift 283 | my %exp = getExports( $base, $eoffset, $size ) 284 | for ( keys %exp ): 285 | if ( $exp{$_} == $procname ): 286 | return $_ 287 | 288 | def getExports: 289 | base = shift 290 | eoffset = shift 291 | size = shift 292 | my %exportlist 293 | 294 | return unless $base && $eoffset && $size 295 | exports = readVirtualMemory( $base + $eoffset, $size ) 296 | 297 | ebase = unpack( "I", substr( $exports, 16, 4 ) ) 298 | enumfuncs = unpack( "I", substr( $exports, 20, 4 ) ) 299 | enumnames = unpack( "I", substr( $exports, 24, 4 ) ) 300 | EATrva = unpack( "I", substr( $exports, 28, 4 ) ) 301 | ENTrva = unpack( "I", substr( $exports, 32, 4 ) ) 302 | EOTrva = unpack( "I", substr( $exports, 36, 4 ) ) 303 | my ( @exportnames, @exportordinals, @exportfunctions ) 304 | 305 | # get ascii name table boundaries 306 | nbegin = readDword( $base + $ENTrva ) 307 | nend = readDword( $base + $ENTrva + ( ( $enumnames - 1 ) * 4 ) ) 308 | lastname = readVirtualMemory( $nend + $base, 255 ) 309 | term = index( $lastname, "\x00" ) 310 | $nend += $term 311 | namebuf = readVirtualMemory( $nbegin + $base, $nend - $nbegin ) 312 | 313 | #print hexasc($namebuf) 314 | 315 | nametable = readVirtualMemory( $ENTrva + $base, $enumnames * 4 ) 316 | functable = readVirtualMemory( $EATrva + $base, $enumfuncs * 4 ) 317 | ordtable = readVirtualMemory( $EOTrva + $base, $enumfuncs * 2 ) 318 | 319 | for ( 0 .. $enumnames - 1 ): 320 | n = unpack( "L", substr( $nametable, $_ * 4, 4 ) ) 321 | if ( $n >= $nbegin ): 322 | ename = substr( $namebuf, $n - $nbegin, 255 ) 323 | $ename =~ s/\x00.*//g 324 | push( @exportnames, $ename ) 325 | 326 | #printf "Adding name index %d (begins at %08x: raw %08x) %s\n", 327 | #$_, $n, $n-$nbegin, $ename 328 | for ( 0 .. $enumfuncs - 1 ): 329 | eord = unpack( "S", substr( $ordtable, $_ * 2, 2 ) ) 330 | push( @exportordinals, $eord ) 331 | for ( 0 .. $enumfuncs - 1 ): 332 | eaddr = unpack( "L", substr( $functable, $_ * 4, 4 ) ) 333 | push( @exportfunctions, $eaddr ) 334 | 335 | for o ( 0 .. $#exportnames ): 336 | name = $exportnames[$o] 337 | ord = $exportordinals[$o] 338 | addr = $exportfunctions[$ord] 339 | $name ||= $ord 340 | $exportlist{ addr + $base } = $name 341 | return %exportlist 342 | 343 | def findRet: 344 | hp 345 | pos 346 | save = $pcontext 347 | $pcontext = \%kernelcontext; # this procedure is kernel context only 348 | for ( 0 .. 100 ): 349 | $hp = $_ 350 | buf = 351 | readVirtualMemory( $kernelbase + 0x1000 + ( $hp * 0x800 ), 0x800 ) 352 | $pos = index( $buf, "\xc3" ) 353 | last unless $pos == -1 354 | ret = $kernelbase + 0x1000 + ( $hp * 0x800 ) + $pos 355 | printf "Found RETN instruction at %08x", $ret 356 | $pcontext = $save 357 | return $ret 358 | 359 | def logical2physical: 360 | logical = shift; # a virtual address in a process 361 | pdb = pcontext['dtb'] 362 | return unless $pdb 363 | offset = $logical & 0xfff; # save byte offset 364 | pde = ( $logical >> 22 ) & 0x3ff 365 | pte = ( $logical >> 12 ) & 0x3ff 366 | buf = readPhysicalMemory( $pdb + ( $pde * 4 ), 4 ) 367 | valid = unpack( "I", $buf ) & 0x1 368 | if ($valid): 369 | ptb = unpack( "I", $buf ) & 0xfffff000 370 | 371 | #printf "Seeking to PTB %08x + PTE %03x * 4 = %08x\n", $ptb, $pte, $ptb + ($pte * 4) 372 | $buf = readPhysicalMemory( $ptb + ( $pte * 4 ), 4 ) 373 | $valid = unpack( "I", $buf ) & 0x1 374 | if ($valid): 375 | phys = unpack( "I", $buf ) & 0xfffff000 376 | return ( $phys | offset ); #restore byte offset 377 | printf "Invalid PTE found for va %08x: %08x\n", $logical, 378 | unpack( "I", $buf ) 379 | return 0 380 | 381 | def listExports: 382 | base = shift 383 | my %pe = parsePE($base) 384 | if ( $pe{'export'] && $pe{'exportsize'] ): 385 | printf "Exports found in PE file at %08x:\n", $base 386 | my %exp = getExports( $base, $pe{'export'], $pe{'exportsize'] ) 387 | for ( sort keys %exp ): 388 | printf "%08x:%s\n", $_, $exp{$_} 389 | else: 390 | print "No export table found\n" 391 | 392 | 393 | 394 | def getEprocess: 395 | pid = shift 396 | j = ( $pid >> 18 ) & 0xff 397 | k = ( $pid >> 10 ) & 0xff 398 | l = ( $pid >> 2 ) & 0xff 399 | save = $pcontext 400 | $pcontext = \%kernelcontext; # this procedure is kernel context only 401 | #print "Finding eprocess[$j][$k][$l]\n" 402 | pspcidtable = getPspCidTable() 403 | 404 | if ($pspcidtable): 405 | subtable 406 | if ( $version >= 6.0 ): 407 | $subtable = readDword($pspcidtable) 408 | else: 409 | table 410 | ptable = readDword($pspcidtable) 411 | if ( $ptable != "failed" ): 412 | 413 | #print("ptable: %08x\n", $ptable 414 | $table = readDword( $ptable + 8 ) 415 | if ( $table != "failed" ): 416 | 417 | #print("table: %08x\n", $table 418 | $subtable = readDword( $table + ( $j * 4 ) ) 419 | if ( ($subtable) && ( $subtable != "failed" ) ): 420 | 421 | #print("subtable: %08x\n", $subtable 422 | subsubtable = readDword( $subtable + ( $k * 4 ) ) 423 | if ( $subsubtable != "failed" ): 424 | 425 | #print("subsubtable: %08x\n", $subsubtable 426 | entry = readDword( $subsubtable + ( $l * 8 ) ) 427 | if ( $entry != "failed" ): 428 | if ( $version < 6 ): 429 | $entry |= 0x80000000; # lock bit 430 | else: 431 | $entry &= 0xfffffffe; # lock bit 432 | 433 | #print("eprocess of pid 0x%x starts at %08x\n", $pid, $entry 434 | $pcontext = $save 435 | return $entry 436 | $pcontext = $save 437 | return 0 438 | 439 | def getProcessList: 440 | ep 441 | my %prochash 442 | my ( $listoffset, $pidoffset, $nameoffset, $timeoffset ) 443 | my ( $threadoffset, $peboffset, $dtboffset ) 444 | save = $pcontext 445 | $pcontext = \%kernelcontext; # this procedure is kernel context only 446 | if ( $version >= 6.0 ): 447 | 448 | # xp, vista 449 | $ep = getEprocess(4) 450 | $listoffset = 0x88 451 | $pidoffset = 0x84 452 | $nameoffset = 0x174 453 | $timeoffset = 0x70 454 | $threadoffset = 0x1b0 455 | $peboffset = 0x1b0 456 | $dtboffset = 0x18 457 | else: 458 | 459 | # win2k 460 | $ep = getEprocess(8) 461 | $listoffset = 0xa0 462 | $pidoffset = 0x9c 463 | $nameoffset = 0x1fc 464 | $timeoffset = 0x88 465 | $threadoffset = 0x1a4 466 | $peboffset = 0x1b0 467 | $dtboffset = 0x18 468 | 469 | #print("System ep: %08x\n", $ep 470 | unless ($ep) { $pcontext = $save; return my @procs = walkList( $ep + $listoffset, $listoffset ) 471 | for eproc (@procs): 472 | e = readVirtualMemory( $eproc, 0x21c ) 473 | if ( len($e) == 0x21c ): 474 | 475 | #print hexformat($e) 476 | name = substr( $e, $nameoffset, 16 ) 477 | $name =~ s/\x00//g 478 | pid = unpack( "I", substr( $e, $pidoffset, 4 ) ) 479 | next unless ($pid) && ( $pid < 0xffff ) 480 | dtb = unpack( "I", substr( $e, $dtboffset, 4 ) ) 481 | peb = unpack( "I", substr( $e, $peboffset, 4 ) ) 482 | created = ft2Time( substr( $e, $timeoffset, 8 ) ) 483 | 484 | my @threads = 485 | walkList( unpack( "I", substr( $e, 0x50, 4 ) ), $threadoffset ) 486 | if (@threads): 487 | $prochash{$eproc}{'pid'] = $pid 488 | $prochash{$eproc}{'name'] = $name 489 | $prochash{$eproc}{'created'] = $created 490 | $prochash{$eproc}{'dtb'] = $dtb 491 | $prochash{$eproc}{'peb'] = $peb 492 | @{ $prochash{$eproc}{'threads'] } = @threads 493 | $pcontext = $save 494 | return %prochash 495 | 496 | def ft2Time: 497 | ft = shift 498 | return 0 unless len($ft) == 8 499 | ch = 0x019db1de 500 | cl = 0xd53e8000 501 | lo = unpack( "I", substr( $ft, 0, 4 ) ) 502 | hi = unpack( "I", substr( $ft, 4, 4 ) ) 503 | return 0 if ( $hi < $ch ) || ( ( $hi == $ch ) && ( $lo < $cl ) ) 504 | return ( ( ( ( $hi * 0x10000 ) * 0x10000 ) + $lo ) - 505 | ( ( ( $ch * 0x10000 ) * 0x10000 ) + $cl ) ) / 10000000 506 | 507 | def walkList: 508 | my @ret 509 | flink = shift; # address of LIST_ENTRY in struct 510 | offset = shift; # offset to LIST_ENTRY from beginning of struct 511 | top = $flink 512 | while ( $flink != 0 ): 513 | push( @ret, $flink - offset ) 514 | $flink = readDword($flink) 515 | last if ( $flink == $top ) || ( $flink == "failed" ) 516 | return @ret 517 | 518 | 519 | def getProcAddress: 520 | module = shift 521 | procname = shift 522 | save = $pcontext 523 | addr 524 | 525 | # get eprocess list, start with bottom process 526 | my %procs = getProcessList() 527 | for ( sort keys %procs ): 528 | dtb = $procs{$_}{'dtb'] 529 | peb = $procs{$_}{'peb'] 530 | pid = $procs{$_}{'pid'] 531 | eprocess = $_ 532 | next unless $peb 533 | print("Searching for %s in modules of pid %x (eprocess is %08x)\n", 534 | $procname, $pid, $eprocess 535 | 536 | # set process context 537 | processcontext['dtb'] = $dtb 538 | processcontext['pid'] = $pid 539 | processcontext['peb'] = $peb 540 | processcontext['eprocess'] = $eprocess 541 | 542 | $pcontext = \%processcontext 543 | 544 | my %modules = getUserModules() 545 | for ( sort keys %modules ): 546 | if ( ( $modules{$_}{'name'] =~ /^$module$/i ) 547 | || ( $modules{$_}{'name'] =~ /^$module\.dll/i ) ) 548 | : 549 | print("Found instance of %s at %08x\n", $module, $_ 550 | my %pe = parsePE($_) 551 | addr = 552 | locateExportNameInTable( $procname, $_, $pe{'export'], 553 | $pe{'exportsize'] ) 554 | goto DONEGOTPROC 555 | DONEGOTPROC: 556 | 557 | # back to original process context 558 | $pcontext = $save 559 | return addr 560 | 561 | def getUserModules: 562 | my %modules 563 | 564 | # read PEB into buf 565 | peb = pcontext['peb'] 566 | pebdata = readVirtualMemory( $peb, 0x300 ) 567 | next unless len($pebdata) == 0x300 568 | 569 | # get module list 570 | mptr = unpack( "I", substr( $pebdata, 0x0c, 4 ) ) 571 | modulelist = readDword( $mptr + 0x14, 4 ) 572 | my @modlist = walkList($modulelist) 573 | for mod (@modlist): 574 | buf = readVirtualMemory( $mod, 0x34 ) 575 | if ( len($buf) == 0x34 ): 576 | base = unpack( "I", substr( $buf, 0x10, 4 ) ) 577 | next if $base == 0 578 | entry = unpack( "I", substr( $buf, 0x14, 4 ) ) 579 | size = unpack( "I", substr( $buf, 0x18, 4 ) ) 580 | path = substr( $buf, 0x1c, 8 ) 581 | name = substr( $buf, 0x24, 8 ) 582 | $modules{$base}{'name'] = unicodeStructToAscii($name) 583 | $modules{$base}{'path'] = unicodeStructToAscii($path) 584 | $modules{$base}{'size'] = $size 585 | $modules{$base}{'entry'] = $entry 586 | return %modules 587 | -------------------------------------------------------------------------------- /windpl_loop.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007 SecureWorks, Inc. 2 | # Copyright (C) 2013 espes 3 | # Copyright (C) 2017 Jannik Vogel 4 | # 5 | # This program is free software subject to the terms of the GNU General 6 | # Public License. You can use, copy, redistribute and/or modify the 7 | # program under the terms of the GNU General Public License as published 8 | # by the Free Software Foundation; either version 3 of the License, or 9 | # (at your option) any later version. You should have received a copy of 10 | # the GNU General Public License along with this program. If not, 11 | # please see http://www.gnu.org/licenses/ for a copy of the GNU General 12 | # Public License. 13 | # 14 | # The program is subject to a disclaimer of warranty and a limitation of 15 | # liability, as disclosed below. 16 | # 17 | # Disclaimer of Warranty. 18 | # 19 | # THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 20 | # APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 21 | # HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT 22 | # WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT 23 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 24 | # PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE 25 | # OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU 26 | # ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, CORRECTION OR 27 | # RECOVERY FROM DATA LOSS OR DATA ERRORS. 28 | # 29 | # Limitation of Liability. 30 | # 31 | # IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 32 | # WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR 33 | # CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 34 | # INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES 35 | # ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT 36 | # NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES 37 | # SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE 38 | # WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN 39 | # ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | #s = IO::Select->new() 49 | #$s->add( \*STDIN ) 50 | #if (serial): 51 | # $s->add( \*FH ) 52 | #elif (client): 53 | # $s->add(client) 54 | 55 | sendReset() 56 | 57 | 58 | def match(text, pattern): 59 | assert(pattern[0] == '/') 60 | assert(pattern[-1] == '/') 61 | return re.search(pattern[1:-1], text) 62 | while (ready = $s->can_read ): 63 | for fh (@ready): 64 | if ( $fh == \*STDIN ): 65 | line = <$fh> 66 | if (match(line, '/break/'): 67 | print("Sending break...\n" 68 | writeDev("b") 69 | if ( $running == 1 ): 70 | print("Kernel is busy (send break command)\n" 71 | elif (match(line, '/processcontext ([0-9A-Fa-f]+)/'): 72 | pid = hex($1) 73 | if ( pid == 0 ): 74 | pcontext = kernelcontext 75 | print("Process context is kernel\n" 76 | else: 77 | eproc = getEprocess(pid) 78 | dtb = readDword( $eproc + 0x18 ) 79 | peb = readDword( $eproc + 0x1b0 ) 80 | 81 | if ($peb): 82 | processcontext['eprocess'] = $eproc 83 | processcontext['dtb'] = dtb 84 | processcontext['peb'] = $peb 85 | processcontext['pid'] = pid 86 | pcontext = \%processcontext 87 | print("Implicit process is now %x\n", pid 88 | else: 89 | print("Invalid PID (PEB not found in eprocess)\n" 90 | 91 | elif (match(line, '/getprocaddress (\S+) (\S+)/'): 92 | dll = $1 93 | export = $2 94 | addr = getProcAddress( dll, export ) 95 | if (addr): 96 | print("%s!%s:%08x\n", dll, export, addr 97 | else: 98 | print("%s!%s not found\n", dll, export 99 | elif (match(line, '/listexports ([0-9A-Fa-f]+)/'): 100 | listExports( hex($1) ) 101 | elif (match(line, '/^logical2physical ([0-9A-Fa-f]+)/'): 102 | print("%08x -> %08x\n", hex($1), logical2physical( hex($1) ) 103 | elif (match(line, '/^parsepe ([0-9A-Fa-f]+)/'): 104 | my %PE = parsePE( hex($1) ) 105 | compiled = localtime( $PE{"TimeDateStamp"] ) 106 | print("Compiled on $compiled\n" 107 | elif (match(line, '/^writevirtualmemory ([0-9A-Fa-f]+) [0-9A-Fa-f][0-9A-Fa-f]/'): 108 | chomp($line) 109 | my ( $c, addr, @bytes ) = split( /\s+/, $line ) 110 | sendDbgKdWriteVirtualMemory( hex(addr), join( "", map { chr(hex) } @bytes ) ) 111 | elif (match(line, '/^(?:messagebox|mb)\s+(.*)\|(.*)/'): 112 | title = $1 113 | message = $2 114 | injectSUSShellcode( $title, $message ) 115 | insertApc() 116 | elif (match(line, '/^processlist|^listprocess/'): 117 | print("Walking process list...\n" 118 | my %procs = getProcessList() 119 | for ( reverse sort keys %procs ): 120 | c = localtime( $procs{$_}{'created'] ) 121 | print("%04x %s\n", $procs{$_}{'pid'], $procs{$_}{'name'] 122 | printf 123 | "Eprocess: %08x DTB: %08x PEB: %08x Created: %s\n", $_, 124 | $procs{$_}{'dtb'], $procs{$_}{'peb'], $c 125 | print("Threads: " 126 | print(join( " ", 127 | map { sprint("%08x", $_ } @{ $procs{$_}{'threads'] } ) 128 | print("\n\n" 129 | elif (match(line, '/^module|^listmodules/'): 130 | my %modules 131 | if ( pcontext['pid'] == 0 ): 132 | %modules = getKernelModules() 133 | else: 134 | %modules = getUserModules() 135 | for ( sort keys %modules ): 136 | print("%s\tPath:%s\n", modules[$_}{'name'], modules[$_}{'path'] 137 | print("base:%08x " . "size:%08x entry:%08x\n\n", $_, modules[$_}{'size'], modules[$_}{'entry'] 138 | elif (match(line, '/^findprocessbyname (\S+)/'): 139 | name = $1 140 | procs = getProcessList() 141 | for proc in procs: 142 | c = localtime(proc['created'] ) 143 | n = proc['name'] 144 | if ( name.lower() == n.lower() ): 145 | #FIXME: !!! 146 | #print("%04x %s\n", $procs{$_}{'pid'], 147 | # $procs{$_}{'name'] 148 | #printf 149 | # "Eprocess: %08x DTB: %08x PEB: %08x Created: %s\n", 150 | # $_, $procs{$_}{'dtb'], $procs{$_}{'peb'], $c 151 | #print("Threads: " 152 | #print(join( " ", 153 | #map { sprint("%08x", $_ @{ $procs{$_}{'threads'] } ) 154 | #print("\n") 155 | break 156 | elif (match(line, '/^eprocess ([0-9A-Fa-f]+)/'): 157 | ep = getEprocess( hex($1) ) 158 | sendDbgKdReadVirtualMemory( $ep, 648 ) 159 | buf = waitStateManipulate(DbgKdReadVirtualMemoryApi) 160 | if ( len(buf) > 56 ): 161 | eproc = substr( buf, 56 ) 162 | if ( len($eproc) > 0x20c ): 163 | name 164 | if ( version > 5 ): 165 | $name = substr( $eproc, 0x174, 16 ) 166 | else: 167 | $name = substr( $eproc, 0x1fc, 16 ) 168 | $name =~ s/\x00//g 169 | print("Process name is $name\n" 170 | next = unpack( "I", substr( $eproc, 0xa0, 4 ) ) 171 | 172 | elif (match(line, '/^bp ([0-9A-Fa-f]+)/'): 173 | sendDbgKdWriteBreakPoint($1) 174 | elif (match(line, '/^bc ([0-9A-Fa-f]+)/'): 175 | sendDbgKdRestoreBreakPoint($1) 176 | elif (match(line, '/^bl/'): 177 | print("Breakpoints:\n", join( "\n", sort keys %breakpoints ), "\n" 178 | elif (match(line, '/^continue/'): 179 | sendDbgKdContinue2() 180 | $running = 1 181 | elif (match(line, '/^getpspcidtable/'): 182 | getPspCidTable() 183 | elif (match(line, '/^(autocontinue|g)$/'): 184 | 185 | # get/set context to update EIP before continuing 186 | my %context = getContext() 187 | context['EIP']++ 188 | setContext(%context) 189 | sendDbgKdContinue2() 190 | $running = 1 191 | elif (match(line, '/^version/'): 192 | printVersionData() 193 | elif (match(line, '/^readcontrolspace/'): 194 | sendDbgKdReadControlSpace() 195 | elif (match(line, '/^writecontrolspace/'): 196 | if ($controlspace): 197 | sendDbgKdWriteControlSpace() 198 | else: 199 | print("Haven't gotten control space yet!\n" 200 | elif (match(line, '/^r (.*)=(.*)/'): 201 | reg = $1 202 | val = $2 203 | my %context = getContext() 204 | if ( len(reg) < 4 ): 205 | reg = uc(reg) 206 | if ( exists context[reg} ): 207 | if ( reg == "fp.RegisterArea" ): 208 | print("Not supported yet.\n" 209 | elif ( reg == "leftovers" ): 210 | print("Not supported.\n" 211 | else: 212 | context[reg} = hex(val) 213 | setContext(%context) 214 | %context = getContext() 215 | print("New value of %s is %08x\n", reg, context[reg} 216 | else: 217 | print("Register reg unknown\n" 218 | elif (match(line, '/^r (.*)/'): 219 | reg = $1 220 | my %context = getContext() 221 | if ( len(reg) < 4 ): 222 | reg = uc(reg) 223 | if ( exists context[reg} ): 224 | if ( reg == "fp.RegisterArea" ): 225 | print("%s = \n%s\n", reg, hexprint(reg) 226 | else: 227 | print("%s = %08x\n", reg, context[reg] 228 | else: 229 | print("Register reg unknown\n" 230 | elif (match(line, '/^r$|^getcontext/'): 231 | my %context = getContext() 232 | for ( sort keys %context ): 233 | if ( ( $_ != "fp.RegisterArea" ) && ( $_ != "leftovers" ) ): 234 | print("%s=%08x\n", $_, context[$_} 235 | elif (match(line, '/^dw ([0-9A-Fa-f]+)/'): 236 | print("%08x: %08x\n", hex($1), readDword( hex($1) ) 237 | elif (match(line, '/^(?:readvirtualmem|d) ([0-9A-Fa-f]+)/'): 238 | vaddr = $1 239 | readlen 240 | if (match(line, '/(?:readvirtualmem|d) ([0-9A-Fa-f]+) ([0-9A-Fa-f]+)/'): 241 | readlen = hex($2) 242 | readlen ||= 4 243 | buf = readVirtualMemory( hex(vaddr), readlen ) 244 | print(hexasc(buf) 245 | elif (match(line, '/^(?:readphysicalmem|dp) ([0-9A-Fa-f]+)/'): 246 | addr = $1 247 | readlen 248 | if (match(line, '/(?:readphysicalmem|dp) ([0-9A-Fa-f]+) ([0-9A-Fa-f]+)/'): 249 | readlen = hex($2) 250 | readlen ||= 4 251 | sendDbgKdReadPhysicalMemory( hex(addr), readlen ) 252 | elif (match(line, '/^reboot/'): 253 | sendDbgKdReboot() 254 | elif (match(line, '/^quit|^exit/'): 255 | sys.exit() 256 | elif (match(line, '/^reset/'): 257 | sendReset() 258 | elif ( $fh == \*FH || $fh == client ): 259 | handlePacket(0) 260 | print("\n\n" 261 | --------------------------------------------------------------------------------