> For the complete documentation index, see [llms.txt](https://www.udayxd.tech/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://www.udayxd.tech/notes/maldev/payload-encryption-xor-and-aes.md).

# Payload Encryption Xor & AES

### Why Do We Need Payload Encryption?

Encrypted:- shellcode is employed to evade static detection. Static detection mechanisms search for signatures within the code to identify potential threats. For instance, in shellcode detection mechanisms like sandboxes, static evasion techniques look for null byte combinations within the shellcode to determine whether it is malicious. By encrypting the payload, we can obfuscate these signatures, making it harder for static analysis tools to recognize and flag the code as malicious.

## **Payload Encryption XOR**

### **Why XOR is Used in Malware:**

1. **Reversible**: If `A + B = C`, then `C+⊕ B = A` Same operation encrypts AND decrypts
2. **Fast**: Extremely efficient computation
3. **Simple**: Easy to implement in any language
4. **Effective**: Breaks signature-based detection

### **Incremental XOR Encryption**

```c
for (i = 0; i < shellcode_size; i++) {
    shellcode[i] = shellcode[i] ^ (bKey + i);
}
```

**How it works:** Each byte uses a DIFFERENT key based on its position in the payload. The key for each position is calculated as the base key plus the position index. So byte 0 gets XORed with `bKey + 0`, byte 1 gets XORed with `bKey + 1`, byte 2 gets XORed with `bKey + 2`, and this pattern continues throughout the entire payload.

**Example with bKey = 'u' (117):**

* Byte 0 → XOR with (117 + 0) = 117 → 'u'
* Byte 1 → XOR with (117 + 1) = 118 → 'v'
* Byte 2 → XOR with (117 + 2) = 119 → 'w'
* Byte 3 → XOR with (117 + 3) = 120 → 'x'
* Byte 4 → XOR with (117 + 4) = 121 → 'y'

**Why it's better than static XOR:** Even if an attacker guesses the correct starting key, each byte requires a different key value because of the incrementing pattern. Automated tools that expect static XOR encryption will fail since they assume the same key works for all bytes. This makes brute-force attempts more difficult and time-consuming.

**Limitations:** There are still only 256 possible starting keys to try. The pattern is predictable since it's just adding the position to the base key. A determined analyst who understands the algorithm can still test all 256 possibilities. This technique is considered obfuscation rather than true cryptographic security.

***

### **Multi-Byte Repeating Key XOR Encryption**

```c
for (size_t i = 0, j = 0; i < sShellcodeSize; i++, j++) {
    if (j >= sKeySize){
        j = 0;
    }
    pShellcode[i] = pShellcode[i] ^ bKey[j];
}
```

**How it works:** Uses a full key consisting of multiple bytes that repeat cyclically across the payload. Two index variables track position: `i` tracks which shellcode byte is being processed, while `j` tracks which key byte is currently being used. Both start at zero and increment together. When `j` reaches the end of the key, it resets back to zero, causing the key to repeat throughout the entire payload.

**Example with key "uday" (4 bytes):**

* Byte 0 → XOR with 'u'
* Byte 1 → XOR with 'd'
* Byte 2 → XOR with 'a'
* Byte 3 → XOR with 'y'
* Byte 4 → XOR with 'u' (key resets and repeats)
* Byte 5 → XOR with 'd'
* Byte 6 → XOR with 'a'
* Byte 7 → XOR with 'y'
* Pattern continues until all bytes are processed

**Security benefits:** Keyspace expands exponentially with key length. A 1-byte key offers only 256 possibilities, but a 4-byte key offers over 4 billion combinations. An 8-byte key offers more than 18 quintillion possibilities. This makes brute-force attacks computationally infeasible for automated tools. Unlike incremental XOR, there is no predictable mathematical relationship between key bytes, making it much harder to crack.

**Important property:** XOR is self-inverse, meaning the same function handles both encryption and decryption. If you pass encrypted data through this function with the same key, it returns the original data because (A XOR B) XOR B = A. This eliminates the need for separate encryption and decryption routines.

**Implementation considerations:** Key length should balance security versus binary size. Use randomly generated bytes instead of ASCII strings to avoid predictability. The key can be hardcoded into the malware, generated at runtime using system entropy, or retrieved from a command and control server.

***

### **Self-Inverse Property of XOR**

**The Magic Property:** XOR is reversible using the same operation. If A XOR B = C, then C XOR B = A. This means encryption and decryption use the exact same code.

**Example:**

```
'H' XOR 'u' = '='   (encryption)
'=' XOR 'u' = 'H'   (decryption - same XOR operation)
```

**Why this matters for malware:**

* No need to write separate encryption and decryption functions
* Reduces code complexity and potential bugs
* Saves space in the malware binary
* Makes implementation simpler and more reliable

***

#### **XOR Encryption Example**

```jsx
#include <stdio.h>
#include <Windows.h>

// Original shellcode (example)
unsigned char RawData[]= "\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50"
"\x52\x51\x56\x48\x31\xd2";

// XOR key
unsigned char bKey[] = "uday";

// XOR encrypt/decrypt function
VOID XorByInputKey(IN PBYTE pShellcode, IN SIZE_T sShellcodeSize, IN PBYTE bKey, IN SIZE_T sKeySize) {
	for (size_t i = 0, j = 0; i < sShellcodeSize; i++, j++) {
		if (j >= sKeySize) {
			j = 0;
		}
		pShellcode[i] = pShellcode[i] ^ bKey[j];
	}
}

int main() {

	printf("[+] Original shellcode:\n");
    for (size_t i = 0; i < sizeof(RawData); i++) {
        printf("\\x%02x", RawData[i]);
    }
    printf("\n\n");

	// encrypt
	printf("Press enter to encrptyed payload \n");
	getchar();
	XorByInputKey(RawData, sizeof(RawData), bKey, sizeof(bKey));

	printf("[+] Encrypted  shellcode:\n");
	for (size_t i = 0; i < sizeof(RawData); i++) {
		printf("\\x%02x", RawData[i]);
	}
	printf("\n\n");

	// decrypt
	printf("Press enter to decrypt payload \n");
	getchar();
	XorByInputKey(RawData, sizeof(RawData), bKey, sizeof(bKey));

	printf("[+] decrypt  shellcode:\n");
	for (size_t i = 0; i < sizeof(RawData); i++) {
		printf("\\x%02x", RawData[i]);
	}
	printf("\n\n");
}
```

**Output Example:**

```jsx
[+] Original shellcode:
\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x00

Press enter to encrptyed payload

[+] Encrypted  shellcode:
\x89\x2c\xe2\x9d\xf0\x9d\xa4\x61\x79\x00\x34\x35\x20\x29\x52\x24\x32\x29\x48\xd2\x75

Press enter to decrypt payload

[+] decrypt  shellcode:
\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x00
```

### How XOR Works with Hex Shellcode and String Key

At its most basic level, everything in a computer is just bytes - numbers from 0 to 255. Whether you're looking at hex shellcode like `\xfc\x48\x83` or a string like "uday", they're all just sequences of bytes stored in memory. The shellcode `\xfc\x48\x83\xe4\xf0` is stored as bytes with decimal values 252, 72, 131, 228, and 240. The key "uday" is stored as bytes with decimal values 117, 100, 97, and 121. When the XOR function runs, it takes each shellcode byte and XORs it with the corresponding key byte. The XOR operation doesn't care about format - it just sees numbers and performs mathematical operations on them. For the first byte, the shellcode value 252 is XORed with the first key byte 117, which gives 137 (displayed as `\x89` in hex). The second byte takes shellcode value 72 and XORs it with the second key byte 100, resulting in 44 (`\x2c`). The third byte uses 131 XOR 97 to get 226 (`\xe2`). The fourth byte uses 228 XOR 121 to get 173 (`\xad`). When we reach the fifth byte, the key has run out, so it resets back to the first key byte 'u' (117). The shellcode value 240 XOR 117 gives 133 (`\x85`). This pattern continues until every byte of the shellcode is processed.

***

## **Payload Encryption - AES Encryption**

***

### Primary Reasons for Using AES in Malware

#### 1. Stronger Protection Against Analysis

AES provides **cryptographic-grade security** that cannot be broken through brute-force attacks. With a 256-bit key, there are 2^256 possible combinations, which is astronomically larger than XOR's 256 possibilities. Even with massive computing power, it would take billions of years to brute-force an AES256 key. This makes it practically impossible for security analysts to decrypt the payload without knowing the key.

#### 2. Resisting Automated Analysis Tools

Modern sandboxes and security tools are equipped with heuristics that detect and break simple XOR encryption. These tools can identify patterns like repeated key bytes or predictable incremental patterns in XOR-encrypted data. AES encryption produces ciphertext that is statistically random and shows no discernible patterns, making it extremely difficult for automated tools to recognize that encryption has even been applied, let alone break it.

#### **AES Encryption**

* symmetric-key algorithm meaning the same key is used for both encryption and decryption. There are several types of AES encryption such as AES128, AES192, and AES256 that vary by the key size. For example, AES128 uses a 128-bit key whereas AES256 uses a 256-bit key.
* AES can use different [block cipher modes of operation](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation) such as CBC, GCM and etc.
* A mode of operation describes how to repeatedly apply a cipher's single-block operation to securely transform amounts of data larger than a block
* Most modes need a unique binary sequence called IV, IV must be non-repeating and for some modes also random. The idea of IV is to make sure distinct cipher texts are produced for same plaintext and key everytime
* If the payload being encrypted is not a multiple of 16 bytes then padding is required to increase the size of the payload and make it a multiple of 16 bytes.
* For both CBC mode and CFB mode, the initialization vector is the size of a block, which for AES is 16 bytes = 128 bits. For [CFB mode](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#CFB), the IV must never be reused for different messages under the same key; for [CBC mode](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#CBC), the IV must never be reused for different messages under the same key, *and* must be unpredictable in advance by an attacker. Using successive integers as the IV is fine for CFB but not fine for CBC.

### What is an IV?

An **Initialization Vector (IV)** is a fixed-size random or pseudo-random value that is used alongside the encryption key to start the encryption process. Think of it as a "starting point" or "initial state" that makes each encryption unique, even when encrypting the exact same data with the exact same key.

### Why is it Called a "Binary Sequence"?

An IV is called a "binary sequence" because it's simply a sequence of bytes (0s and 1s) - just like any other data on a computer. In AES, the IV is always **16 bytes (128 bits)**, which is the same size as a single AES block. These 16 bytes are just a random pattern of bits like `10110101 00111010 11110000 ...`

**Example of a 16-byte IV in hex**

```
B4 C8 1D 1D 14 7C CB FA 07 42 D9 ED 1A 86 D9 CD
```

This is just 16 random numbers, but in binary it's 128 bits of random data.

#### AES Using WinAPIs (bCrypt Library)

bCrypt library ([bcrypt.h](https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/))

**AES Structure**

To start, an `AES` structure is created which contains the required data to perform encryption and decryption.

```
typedef struct _AES {

	PBYTE	pPlainText;         // base address of the plain text data
	DWORD	dwPlainSize;        // size of the plain text data

	PBYTE	pCipherText;        // base address of the encrypted data
	DWORD	dwCipherSize;       // size of it (this can change from dwPlainSize in case there was padding)

	PBYTE	pKey;               // the 32 byte key
	PBYTE	pIv;                // the 16 byte iv

} AES, *PAES;
```

***

#### **Cryptographic Next Generation**

CNG Provides a set of cryptographic functions that can be used by OS applications. So it provides a standard interface for cryptographic operations, making it easier for developers to implement security features in their applications. Replaces the old CryptoAPI.

The InstallAesEncryption and InstallAesDecryption both make use of CNG:

The BCrypt Library functions used are as follows:

* [BCryptOpenAlgorithmProvider](https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptopenalgorithmprovider) - Used to load the [BCRYPT\_AES\_ALGORITHM](https://learn.microsoft.com/en-us/windows/win32/seccng/cng-algorithm-identifiers) Cryptographic Next Generation (CNG) provider to enable the use of cryptographic functions.
* [BCryptGetProperty](https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgetproperty) - This function is called twice, the first time to retrieve the value of [BCRYPT\_OBJECT\_LENGTH](https://learn.microsoft.com/en-us/windows/win32/seccng/cng-property-identifiers) and the second time to fetch the value of [BCRYPT\_BLOCK\_LENGTH](https://learn.microsoft.com/en-us/windows/win32/seccng/cng-property-identifiers) property identifiers.
* [BCryptSetProperty](https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptsetproperty) - Used to initialize the `BCRYPT_OBJECT_LENGTH` property identifier.
* [BCryptGenerateSymmetricKey](https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgeneratesymmetrickey) - Used to create a key object from the input AES key specified.
* [BCryptEncrypt](https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptencrypt) - Used to encrypt a specified block of data. This function is called twice, the first time retrieves the size of the encrypted data to allocate a heap buffer of that size. The second call encrypts the data and stores the ciphertext in the allocated heap.
* [BCryptDestroyKey](https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptdestroykey) - Used to clean up by destroying the key object created using `BCryptGenerateSymmetricKey`.
* [BCryptCloseAlgorithmProvider](https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptclosealgorithmprovider) - Used to clean up by closing the object handle of the algorithm provider created earlier using `BCryptOpenAlgorithmProvider`.
* [BCryptDecrypt](https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptdecrypt)
* Used to decrypt a specified block of data. This function is called twice, the first time retrieves the size of the decrypted data to allocate a heap buffer of that size. The second call decrypts the data and stores the plaintext data in the allocated heap.

**Padding**

Both `InstallAesEncryption` and `InstallAesDecryption` functions use the `BCRYPT_BLOCK_PADDING` flag with the `BCryptEncrypt` and `BCryptDecrypt` bcrypt functions respectively, which will automatically pad the input buffer, if required, to be a multiple of 16 bytes, solving the AES padding issue.

#### Additional Helper Functions:

1. The first Function: `PrintHexData`, prints an input buffer as a char array in C to the console.

```c
// Print the input buffer as a hex char array
VOID PrintHexData(LPCSTR Name, PBYTE Data, SIZE_T Size) {
	printf("unsigned char %s[] = {", Name);
	for (int i = 0; i < Size; i++) {
		if (i % 16 == 0) { // Each block on one line
			printf("\n\t");
		}
		if (i < Size - 1) {
			printf("0x%0.2X, ", Data[i]); //seperating each bytes with ,
		}
		else {
			printf("0x%0.2X ", Data[i]); //last byte
		}
	}
	printf("};\n\n\n"); //closing the array
	
}
```

1. Second is `GenerateRandomBytes`, Fills up an input buffer with random bytes, which in this case are used to generate a random key and IV

```c
VOID GenerateRandomBytes(PBYTE pByte, SIZE_T sSize) {
	for (int i = 0; i < sSize; i++) {
		pByte[i] = (BYTE)rand() % 0xFF;
	}
}
```

Encryption Implementaion:

```c
#include <stdio.h>
#include <windows.h>
#include <bcrypt.h>
#include <time.h>
#pragma comment(lib, "Bcrypt.lib")

#define KEYSIZE 32
#define IVSIZE 16
#define NT_SUCCESS(status)	        (((NTSTATUS)(status)) >= 0)

typedef struct _AES {
	PBYTE pPlainText;
	DWORD dwPlainSize;

	PBYTE pCipherText;
	DWORD dwCipherSize;

	PBYTE pKey;
	PBYTE pIv;

} AES, * PAES;

// Print the input buffer as a hex char array
VOID PrintHexData(LPCSTR Name, PBYTE Data, SIZE_T Size) {
	printf("unsigned char %s[] = {", Name);
	for (int i = 0; i < Size; i++) {
		if (i % 16 == 0) { // Each block on one line
			printf("\n\t");
		}
		if (i < Size - 1) {
			printf("0x%0.2X, ", Data[i]); //seperating each bytes with ,
		}
		else {
			printf("0x%0.2X ", Data[i]); //last byte
		}
	}
	printf("};\n\n\n"); //closing the array

}

BOOL InstallAesEncryption(PAES pAes) {
	/*Passing by reference, because we need to modify the actual struct and not its copy*/

	/*Initialising imp values*/
	BOOL bSTATE = TRUE;
	BCRYPT_ALG_HANDLE hAlgorithm = NULL;
	BCRYPT_KEY_HANDLE hKeyHandle = NULL;

	ULONG cbResult = NULL;
	DWORD dwBlockSize = NULL;

	DWORD cbKeyObject = NULL;
	PBYTE pbKeyObject = NULL;

	PBYTE pbCipherText = NULL;
	DWORD cbCipherText = NULL;

	NTSTATUS STATUS = NULL;

	// Initialising "hAlgorithm" as AES algo handle

	STATUS = BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_AES_ALGORITHM, NULL, 0);
	if (!NT_SUCCESS(STATUS)) {
		printf("[!] BCryptOpenAlgorithmProvider failed with error: 0x%0.8X\n", STATUS);
		bSTATE = FALSE; goto _EndOfFunc;
	}

	//Getting the size of the key object variable pKeyObject. This is used by the BCryptGenerateSymmetricKey 
	//..function later.

	STATUS = BCryptGetProperty(hAlgorithm, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbKeyObject, sizeof(DWORD), &cbResult, 0);
	if (!NT_SUCCESS(STATUS)) {
		printf("[!] BCryptGetProperty[1] failed with Error: 0x%0.8X\n", STATUS);
		bSTATE = FALSE; goto _EndOfFunc;
	}

	//Getting the size of block used in encryption. Since this is AES it must be 16 bytes.
	STATUS = BCryptGetProperty(hAlgorithm, BCRYPT_BLOCK_LENGTH, (PBYTE)&dwBlockSize, sizeof(DWORD), &cbResult, 0);
	if (!NT_SUCCESS(STATUS)) {
		printf("[!] BCryptGetProperty[2] failed with Error: 0x%0.8X\n", STATUS);
		bSTATE = FALSE; goto _EndOfFunc;
	}

	if (dwBlockSize != 16) {
		bSTATE = FALSE; goto _EndOfFunc;
	}

	//Allocating memory for the key object
	pbKeyObject = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbKeyObject);
	if (pbKeyObject == NULL) {
		bSTATE = FALSE; goto _EndOfFunc;
	}

	//Setting Block Cipher Mode to CBC, uses 32 byte key and 16byte IV
	STATUS = BCryptSetProperty(hAlgorithm, BCRYPT_CHAINING_MODE, (PBYTE)BCRYPT_CHAIN_MODE_CBC, sizeof(BCRYPT_CHAIN_MODE_CBC), 0);
	if (!NT_SUCCESS(STATUS)) {
		printf("[!] BCryptSetProperty Failed with Error: 0x%0.8X \n", STATUS);
		bSTATE = FALSE; goto _EndOfFunc;
	}

	//Generating the key object from the AES key "pAes->pKey". The output will be saved in pKeyObject and will be size cbKeyObject
	STATUS = BCryptGenerateSymmetricKey(hAlgorithm, &hKeyHandle, pbKeyObject, cbKeyObject, (PBYTE)pAes->pKey, KEYSIZE, 0);
	if (!NT_SUCCESS(STATUS)) {
		printf("[!] BCryptGenerateSymmetricKey Failed with Error: 0x%0.8X \n", STATUS);
		bSTATE = FALSE; goto _EndOfFunc;
	}

	//Running BCryptEncrypt first time with NULL output parameters to retrieve the size of the output buffer which is saved in cbCipherText
	STATUS = BCryptEncrypt(hKeyHandle, (PUCHAR)pAes->pPlainText, (ULONG)pAes->dwPlainSize, NULL, pAes->pIv, IVSIZE, NULL, 0, &cbCipherText, BCRYPT_BLOCK_PADDING);
	if (!NT_SUCCESS(STATUS)) {
		printf("[!] BCryptEncrpt[2] Failed with Error: 0x%0.8X\n", STATUS);
		bSTATE = FALSE; goto _EndOfFunc;
	}

	// Allocating enough memory for the output buffer, cbCipherText
	pbCipherText = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbCipherText);
	if (pbCipherText == NULL) {
		bSTATE = FALSE; goto _EndOfFunc;
	}

	// Running BCryptEncrypt again with pbCipherText as the output buffer
	STATUS = BCryptEncrypt(hKeyHandle, (PUCHAR)pAes->pPlainText, (ULONG)pAes->dwPlainSize, NULL, pAes->pIv, IVSIZE, pbCipherText, cbCipherText, &cbResult, BCRYPT_BLOCK_PADDING);
	if (!NT_SUCCESS(STATUS)) {
		printf("[!] BCryptEncrypt[2] Failed With Error: 0x%0.8X \n", STATUS);
		bSTATE = FALSE; goto _EndOfFunc;
	}

	//Cleanup
_EndOfFunc:
	if (hKeyHandle)
		BCryptDestroyKey(hKeyHandle);
	if (hAlgorithm)
		BCryptCloseAlgorithmProvider(hAlgorithm, 0);
	if (pbKeyObject)
		HeapFree(GetProcessHeap(), 0, pbKeyObject);
	if (pbCipherText != NULL && bSTATE) {
		//If everything worked, save pbCipherText and cbCipherText
		pAes->pCipherText = pbCipherText;
		pAes->dwCipherSize = cbCipherText;
	}
	return bSTATE;
}

BOOL SimpleEncryption(_In_ PVOID pPlainTextData, _In_ DWORD sPlainTextSize, _In_ PBYTE pKey, _In_ PBYTE pIv,
	_Out_ PVOID* pCipherTextData, _Out_ DWORD* sCipherTextSize) {

	if (pPlainTextData == NULL || sPlainTextSize == NULL || pKey == NULL || pIv == NULL)
		return FALSE;

	AES Aes;
	Aes.pPlainText = (PBYTE)pPlainTextData;
	Aes.dwPlainSize = sPlainTextSize;
	Aes.pKey = pKey;
	Aes.pIv = pIv;

	if (!InstallAesEncryption(&Aes)) {
		return FALSE;
	}

	*pCipherTextData = Aes.pCipherText;
	*sCipherTextSize = Aes.dwCipherSize;

	return TRUE;
}

	//Plain text
	// this is the following string in hex "This is a plain text string, we'll try to encrypt/decrypt !"
unsigned char Data[] = {
	0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x70, 0x6C,
	0x61, 0x69, 0x6E, 0x20, 0x74, 0x65, 0x78, 0x74, 0x20, 0x73, 0x74, 0x72,
	0x69, 0x6E, 0x67, 0x2C, 0x20, 0x77, 0x65, 0x27, 0x6C, 0x6C, 0x20, 0x74,
	0x72, 0x79, 0x20, 0x74, 0x6F, 0x20, 0x65, 0x6E, 0x63, 0x72, 0x79, 0x70,
	0x74, 0x2F, 0x64, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x20, 0x21
};

int main() {
	BYTE pKey[KEYSIZE];
	BYTE pIv[IVSIZE];

	srand(time(NULL)); // seed to generate the key. used to further randomise the key
	GenerateRandomBytes(pKey, KEYSIZE); //generating a key
	srand(time(NULL) ^ pKey[0]); //the seed to generate the IV. use the first byte of the key to add more randomness.
	GenerateRandomBytes(pIv, IVSIZE); // generating IV

	//printing key and iv
	PrintHexData("pKey", pKey, KEYSIZE);
	PrintHexData("pIv", pIv, IVSIZE);

	//Defining two variables, the output buffer and its respective size which will be used by SimpleEncryption
	PVOID pCipherText = NULL;
	DWORD dwCipherSize = NULL;
	
	printf("Data: %s \n\n", Data);
	
	//Encryption
	if (!SimpleEncryption(Data, sizeof(Data), pKey, pIv, &pCipherText, &dwCipherSize)) {
		return -1;
	}

	//print the encrypted buffer as a hex array
	PrintHexData("CipherText", (PBYTE)pCipherText, dwCipherSize);

	//Cleanup
	HeapFree(GetProcessHeap(), 0, pCipherText);
	system("PAUSE");
	return 0;
}

```

Output:

<figure><img src="https://3173583452-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F992MXD5taJKwdsEBglpC%2Fuploads%2Fgit-blob-f3a884a002789c085dbf3a7e73ec10ef60d667a9%2Fimage%20(73).png?alt=media" alt=""><figcaption></figcaption></figure>

Note that the cipher texts dont match because we are using IV.

Decryption Implementaion:

```c
#include <stdio.h>
#include <windows.h>
#include <bcrypt.h>

#pragma comment(lib, "Bcrypt.lib")

#define KEYSIZE 32
#define IVSIZE 16
#define NT_SUCCESS(status)	        (((NTSTATUS)(status)) >= 0)

typedef struct _AES {
	PBYTE pPlainText;
	DWORD dwPlainSize;

	PBYTE pCipherText;
	DWORD dwCipherSize;

	PBYTE pKey;
	PBYTE pIv;

} AES, * PAES;

// Print the input buffer as a hex char array
VOID PrintHexData(LPCSTR Name, PBYTE Data, SIZE_T Size) {
	printf("unsigned char %s[] = {", Name);
	for (int i = 0; i < Size; i++) {
		if (i % 16 == 0) { // Each block on one line
			printf("\n\t");
		}
		if (i < Size - 1) {
			printf("0x%0.2X, ", Data[i]); //seperating each bytes with ,
		}
		else {
			printf("0x%0.2X ", Data[i]); //last byte
		}
	}
	printf("};\n\n\n"); //closing the array

}

BOOL InstallAesDecryption(PAES pAes) {
	BOOL bSTATE = TRUE;
	BCRYPT_ALG_HANDLE hAlgorithm = NULL;
	BCRYPT_KEY_HANDLE hKeyHandle = NULL;

	ULONG cbResult = 0; // FIXED: NULL -> 0
	DWORD dwBlockSize = 0; // FIXED: NULL -> 0

	DWORD cbKeyObject = 0; // FIXED: NULL -> 0
	PBYTE pbKeyObject = NULL;

	PBYTE pbPlainText = NULL;
	DWORD cbPlainText = 0; // FIXED: NULL -> 0
	NTSTATUS STATUS = 0; // FIXED: NULL -> 0

	//Initialising the "hAlgorithm" as AES algorithm handle
	STATUS = BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_AES_ALGORITHM, NULL, 0);
	if (!NT_SUCCESS(STATUS)) {
		printf("[!] BCryptOpenAlgorithmProvided Failed with Error: 0x%0.8X\n", STATUS);
		bSTATE = FALSE; goto _EndOfFunc;
	}

	// Getting the size of the key object variable pbKeyObject. This is used by the BCryptGenerateSymmetricKey function later
	STATUS = BCryptGetProperty(hAlgorithm, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbKeyObject, sizeof(DWORD), &cbResult, 0);
	if (!NT_SUCCESS(STATUS)) {
		printf("[!] BCryptGetProperty[1] Failed With Error: 0x%0.8X \n", STATUS);
		bSTATE = FALSE; goto _EndOfFunc;
	}

	//Getting the size of the block used in encryption. since its AES it should be 16 bytes
	STATUS = BCryptGetProperty(hAlgorithm, BCRYPT_BLOCK_LENGTH, (PBYTE)&dwBlockSize, sizeof(DWORD), &cbResult, 0);
	if (!NT_SUCCESS(STATUS)) {
		printf("[!] BCryptGetProperty Failed with Error: 0x%0.8X\n", STATUS);
		bSTATE = FALSE; goto _EndOfFunc;
	}

	//Checking if Block Size is 16 bytes
	if (dwBlockSize != 16) {
		bSTATE = FALSE; goto _EndOfFunc;
	}

	// Allocating Memory for the key object
	pbKeyObject = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbKeyObject);
	if (pbKeyObject == NULL) {
		bSTATE = FALSE; goto _EndOfFunc;
	}

	//Setting block cipher mode to CBC. 
	STATUS = BCryptSetProperty(hAlgorithm, BCRYPT_CHAINING_MODE, (PBYTE)BCRYPT_CHAIN_MODE_CBC, sizeof(BCRYPT_CHAIN_MODE_CBC), 0);
	if (!NT_SUCCESS(STATUS)) {
		printf("[!] BCryptSetProperty Failed With Error: 0x%0.8X\n", STATUS);
		bSTATE = FALSE; goto _EndOfFunc;
	}

	// Generating the key object from the AES key "pAes->pKey". The output will be saved in pbKeyObject of size cbKeyObject
	STATUS = BCryptGenerateSymmetricKey(hAlgorithm, &hKeyHandle, pbKeyObject, cbKeyObject, pAes->pKey, KEYSIZE, 0);
	if (!NT_SUCCESS(STATUS)) {
		printf("[!] BCryptGenerateSymmetricKey Failed with Error: 0x%0.8X\n", STATUS);
		bSTATE = FALSE; goto _EndOfFunc;
	}

	//Running BCryptDecrypt first time with NULL output parameters to retrieve the size of the output buffer which is saved in plain text
	STATUS = BCryptDecrypt(hKeyHandle, (PUCHAR)pAes->pCipherText, (ULONG)pAes->dwCipherSize, NULL, pAes->pIv, IVSIZE, NULL, 0, &cbPlainText, BCRYPT_BLOCK_PADDING);
	if (!NT_SUCCESS(STATUS)) {
		printf("[!] BCryptDecrypt[1] Failed with Error: 0x%0.8X\n", STATUS);
		bSTATE = FALSE; goto _EndOfFunc;
	}

	//Allocating enough memory for the output buffer, cbPlainText:
	pbPlainText = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbPlainText);
	if (pbPlainText == NULL) {
		bSTATE = FALSE; goto _EndOfFunc;
	}

	//Running BCryptDecrypt again with pbPlainText as the output buffer
	STATUS = BCryptDecrypt(hKeyHandle, (PUCHAR)pAes->pCipherText, (ULONG)pAes->dwCipherSize, NULL, pAes->pIv, IVSIZE, pbPlainText, cbPlainText, &cbResult, BCRYPT_BLOCK_PADDING);
	if (!NT_SUCCESS(STATUS)) {
		printf("[!] BCryptDecrypt[2] Failed with Error: 0x%0.8X\n", STATUS);
		bSTATE = FALSE; goto _EndOfFunc;
	}

_EndOfFunc:
	if (hKeyHandle)
		BCryptDestroyKey(hKeyHandle);
	if (hAlgorithm)
		BCryptCloseAlgorithmProvider(hAlgorithm, 0);
	if (pbKeyObject)
		HeapFree(GetProcessHeap(), 0, pbKeyObject);
	if (pbPlainText != NULL && bSTATE) {
		pAes->pPlainText = pbPlainText;
		pAes->dwPlainSize = cbPlainText;
	}
	return bSTATE;
}

BOOL SimpleDecryption(_In_ PVOID pCipherTextData, _In_ DWORD sCipherTextSize, _In_ PBYTE pKey, _In_ PBYTE pIv,
	_Out_ PVOID* pPlainTextData, OUT DWORD* sPlainTextSize) {

	// FIXED: sCipherTextSize is DWORD, not pointer
	if (pCipherTextData == NULL || sCipherTextSize == 0 || pKey == NULL || pIv == NULL)
		return FALSE;

	AES DAes = { 0 };
	DAes.pKey = pKey;
	DAes.pIv = pIv;
	DAes.pCipherText = (PBYTE)pCipherTextData;
	DAes.dwCipherSize = sCipherTextSize;

	if (!InstallAesDecryption(&DAes)) {
		return FALSE;
	}

	*pPlainTextData = DAes.pPlainText;
	*sPlainTextSize = DAes.dwPlainSize;
	return TRUE;

}

// UPDATED: New key data
unsigned char pKey[] = {
	0x8A, 0x5B, 0x53, 0xD4, 0x3C, 0x8D, 0x9B, 0xEA, 0x70, 0x7F, 0xC6, 0xA2, 0xCC, 0xA5, 0xE0, 0x37,
	0x99, 0x4F, 0xEE, 0x7C, 0x66, 0x62, 0x24, 0xEA, 0xBA, 0x05, 0x19, 0xD4, 0xF9, 0x33, 0xA6, 0x5F };

// UPDATED: New IV data
unsigned char pIv[] = {
	0x76, 0x04, 0x4A, 0xA7, 0xD1, 0x4B, 0xFE, 0x7A, 0xE3, 0x62, 0x93, 0x4A, 0x6F, 0xCD, 0x22, 0x57 };

// UPDATED: New ciphertext data
unsigned char CipherText[] = {
	0xA9, 0xCB, 0xB1, 0x6E, 0x7A, 0x82, 0x27, 0xDD, 0x61, 0x1E, 0x0A, 0xF7, 0xFA, 0xA0, 0x06, 0xE3,
	0xDD, 0x47, 0x8B, 0xF5, 0x61, 0xEE, 0x03, 0xA6, 0x33, 0xE9, 0x0E, 0x1E, 0x1E, 0x45, 0x85, 0x27,
	0xB6, 0x2F, 0x9A, 0x73, 0x12, 0x93, 0x88, 0xB9, 0x28, 0x07, 0xDB, 0x8C, 0x31, 0x03, 0x10, 0x8D,
	0x59, 0x43, 0x25, 0x9E, 0x86, 0x88, 0x2D, 0xE6, 0xF7, 0x48, 0x93, 0x55, 0x4B, 0xAB, 0xE4, 0x3A };

//Decryption
int main() {
	//Defining two variables the output buffer and its respective size which will be used in SimpleDecryption
	PVOID pPlaintext = NULL;
	DWORD dwPlainSize = 0; // FIXED: NULL -> 0

	//Decrypting
	if (!SimpleDecryption(CipherText, sizeof(CipherText), pKey, pIv, &pPlaintext, &dwPlainSize)) {
		return -1;
	}

	//Printing the decrypted data to the screen in hex format
	PrintHexData("PlainText", (PBYTE)pPlaintext, dwPlainSize);

	//this will print: "This is a plain text string, we'll try to encrypt/decrypt !"
	printf("Data: %s \n", pPlaintext);

	//Clean up
	HeapFree(GetProcessHeap(), 0, pPlaintext);
	system("PAUSE");
	return 0;
}
```

Output:

<figure><img src="https://3173583452-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F992MXD5taJKwdsEBglpC%2Fuploads%2Fgit-blob-9a7067e1569c28191c4b8d6a85394daa72bca4ae%2Fimage%20(74).png?alt=media" alt=""><figcaption></figcaption></figure>

**Drawbacks:**

One of the primary drawbacks of using BCrypt is that the usage of the cryptographic WinAPIs results them being visible in the binary’s Import Address Table (IAT). Security solutions can detect the use of cryptographic functions by scanning the IAT, which can potentially indicate malicious behaviour or raise suspicion. Hiding WinAPIs in the IAT is possible.

As of now this is how IAT looks with out **IAT Hooking:**

<figure><img src="https://3173583452-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F992MXD5taJKwdsEBglpC%2Fuploads%2Fgit-blob-b3f76076b4abca5fa9db7991bdfd7330e13222a6%2Fimage%20(75).png?alt=media" alt=""><figcaption></figcaption></figure>

#### AES Using Tiny-AES Library

This section makes use of the [tiny-AES-c](https://github.com/kokke/tiny-AES-c) third-party encryption library tha performs AES encryption without the use of WinAPIs. Tiny-AES-C is a small portable library that can perform AES128/192/256 in C.

**Setting Up Tiny-AES**

To begin using Tiny-AES there are two requirements:

1. Include `aes.hpp` (C++) or include `aes.h` (C) in the project.
2. Add the `aes.c` file to the project.

**Setting The AES256 Flag**

By default the library applies the AES128 algorithm. One can enable others by enabling one of [AESXXX flags](https://github.com/kokke/tiny-AES-c/blob/master/aes.h#L27) located in the `aes.h` and commenting the other flags accordingly.

eg: for AES256, aes.h would look like:

```c
//#define AES128 1
//#define AES192 1
#define AES256 1
```

**Drawbacks:**

1. Does not support padding. All buffers must be multiples of 16 bytes.
2. The [arrays](https://github.com/kokke/tiny-AES-c/blob/master/aes.c#L79) used in the library can be signatured by security solutions to detect the use of Tiny-AES. These arrays are used to apply AES algorithm and hence is a requirement to have in the code. Though it is possible to modify their signature using different ways. One solution is to XOR these arrays and decrypt them at runtime right before calling the initialisation function, `AES_init_ctx_iv` .

**Custom Padding Function:**

The lack of padding support can be solved by creating a custom padding function.

```c
BOOL PaddBuffer(_In_ PBYTE InputBuffer, _In_ SIZE_T InputBufferSize, _Out_ PBYTE* OutputPaddedBuffer, _Out_ SIZE_T* OutputPaddedSize) {
	PBYTE PaddedBuffer = NULL;
	SIZE_T PaddedSize = NULL;

	//calculate the nearest number that is multiple of 16 and saving it to PaddedSize
	PaddedSize = InputBufferSize + 16 - (InputBufferSize % 16);
	//allocating buffer of size "PaddedSize"
	PaddedBuffer = (PBYTE)HeapAlloc(GetProcessHeap, 0, PaddedSize);
	if (!PaddedBuffer) {
		return FALSE;
	}
	//cleaning the allocated buffer
	ZeroMemory(PaddedBuffer, PaddedSize);

	//copying the old buffer to the new padded buffer
	memcpy(PaddedBuffer, InputBuffer, InputBufferSize);

	//saving result:
	*OutputPaddedBuffer = PaddedBuffer;
	*OutputPaddedSize = PaddedSize;

}
```

Encryption:

```c
#include <windows.h>
#include <stdio.h>
#include <time.h>
#include "aes.h"

#define KEYSIZE 32
#define IVSIZE 16

BOOL PaddBuffer(_In_ PBYTE InputBuffer, _In_ SIZE_T InputBufferSize, _Out_ PBYTE* OutputPaddedBuffer, _Out_ SIZE_T* OutputPaddedSize) {
	PBYTE PaddedBuffer = NULL;
	SIZE_T PaddedSize = NULL;

	//calculate the nearest number that is multiple of 16 and saving it to PaddedSize
	PaddedSize = InputBufferSize + 16 - (InputBufferSize % 16);
	//allocating buffer of size "PaddedSize"
	PaddedBuffer = (PBYTE)HeapAlloc(GetProcessHeap(), 0, PaddedSize);
	if (!PaddedBuffer) {
		return FALSE;
	}
	//cleaning the allocated buffer
	ZeroMemory(PaddedBuffer, PaddedSize);

	//copying the old buffer to the new padded buffer
	memcpy(PaddedBuffer, InputBuffer, InputBufferSize);

	//saving result:
	*OutputPaddedBuffer = PaddedBuffer;
	*OutputPaddedSize = PaddedSize;

}
// Generate random bytes of size sSize
VOID GenerateRandomBytes(PBYTE pByte, SIZE_T sSize) {

	for (int i = 0; i < sSize; i++) {
		pByte[i] = (BYTE)rand() % 0xFF;
	}

}

// Print the input buffer as a hex char array
VOID PrintHexData(LPCSTR Name, PBYTE Data, SIZE_T Size) {

	printf("unsigned char %s[] = {", Name);

	for (int i = 0; i < Size; i++) {
		if (i % 16 == 0)
			printf("\n\t");

		if (i < Size - 1) {
			printf("0x%0.2X, ", Data[i]);
		}
		else {
			printf("0x%0.2X ", Data[i]);
		}
	}
	printf("};\n\n\n");
}

// "this is plaintext string, we'll try to encrypt... lets hope everything goes well :)" in hex
// since the upper string is 82 byte in size, and 82 is not mulitple of 16, we cant encrypt this directly using tiny-aes
unsigned char Data[] = {
	0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x70, 0x6C, 0x61, 0x6E,
	0x65, 0x20, 0x74, 0x65, 0x78, 0x74, 0x20, 0x73, 0x74, 0x69, 0x6E, 0x67,
	0x2C, 0x20, 0x77, 0x65, 0x27, 0x6C, 0x6C, 0x20, 0x74, 0x72, 0x79, 0x20,
	0x74, 0x6F, 0x20, 0x65, 0x6E, 0x63, 0x72, 0x79, 0x70, 0x74, 0x2E, 0x2E,
	0x2E, 0x20, 0x6C, 0x65, 0x74, 0x73, 0x20, 0x68, 0x6F, 0x70, 0x65, 0x20,
	0x65, 0x76, 0x65, 0x72, 0x79, 0x74, 0x68, 0x69, 0x67, 0x6E, 0x20, 0x67,
	0x6F, 0x20, 0x77, 0x65, 0x6C, 0x6C, 0x20, 0x3A, 0x29, 0x00
};

int main() {
	//struct needed for  Tiny-AES library
	struct AES_ctx ctx;
	BYTE pKey[KEYSIZE];
	BYTE pIv[IVSIZE];

	srand(time(NULL));
	GenerateRandomBytes(pKey, KEYSIZE);
	srand(time(NULL) ^ pKey[0]);
	GenerateRandomBytes(pIv, IVSIZE);

	PrintHexData("pKey", pKey, KEYSIZE);
	PrintHexData("pIv", pIv, IVSIZE);

	//Initialising the Tiny-AES lib
	AES_init_ctx_iv(&ctx, pKey, pIv);

	//Initialising variables that will hold the new buffer base address in the case where padding is required and its size
	PBYTE PaddedBuffer = NULL;
	SIZE_T PAddedSize = NULL;

	//Padding the buffer if required
	if (sizeof(Data) % 16 != 0) {
		PaddBuffer(Data, sizeof(Data), &PaddedBuffer, &PAddedSize);
		//Encrypting the padded buffer instead
		AES_CBC_encrypt_buffer(&ctx, PaddedBuffer, PAddedSize);
		//Printing Buffer
		PrintHexData("CipherText", PaddedBuffer, PAddedSize);
	}
	else {
		AES_CBC_encrypt_buffer(&ctx, Data, sizeof(Data));
		PrintHexData("Ciphertext", Data, sizeof(Data));
	}
	//Freeing Paddedbuffer, if necessary
	if (PaddedBuffer != NULL) {
		HeapFree(GetProcessHeap(), 0, PaddedBuffer);
	}
	system("PAUSE");

}
```

Output:

<figure><img src="https://3173583452-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F992MXD5taJKwdsEBglpC%2Fuploads%2Fgit-blob-9265f9c564dae568dc006cfc5de6eb485f168956%2Fimage%20(76).png?alt=media" alt=""><figcaption></figcaption></figure>

Decryption:

```c
#include <windows.h>
#include <stdio.h>
#include <time.h>
#include "aes.h"

#define KEYSIZE 32
#define IVSIZE 16

BOOL PaddBuffer(_In_ PBYTE InputBuffer, _In_ SIZE_T InputBufferSize, _Out_ PBYTE* OutputPaddedBuffer, _Out_ SIZE_T* OutputPaddedSize) {
	PBYTE PaddedBuffer = NULL;
	SIZE_T PaddedSize = NULL;

	//calculate the nearest number that is multiple of 16 and saving it to PaddedSize
	PaddedSize = InputBufferSize + 16 - (InputBufferSize % 16);
	//allocating buffer of size "PaddedSize"
	PaddedBuffer = (PBYTE)HeapAlloc(GetProcessHeap(), 0, PaddedSize);
	if (!PaddedBuffer) {
		return FALSE;
	}
	//cleaning the allocated buffer
	ZeroMemory(PaddedBuffer, PaddedSize);

	//copying the old buffer to the new padded buffer
	memcpy(PaddedBuffer, InputBuffer, InputBufferSize);

	//saving result:
	*OutputPaddedBuffer = PaddedBuffer;
	*OutputPaddedSize = PaddedSize;

}
// Generate random bytes of size sSize
VOID GenerateRandomBytes(PBYTE pByte, SIZE_T sSize) {

	for (int i = 0; i < sSize; i++) {
		pByte[i] = (BYTE)rand() % 0xFF;
	}

}

// Print the input buffer as a hex char array
VOID PrintHexData(LPCSTR Name, PBYTE Data, SIZE_T Size) {

	printf("unsigned char %s[] = {", Name);

	for (int i = 0; i < Size; i++) {
		if (i % 16 == 0)
			printf("\n\t");

		if (i < Size - 1) {
			printf("0x%0.2X, ", Data[i]);
		}
		else {
			printf("0x%0.2X ", Data[i]);
		}
	}
	printf("};\n\n\n");
}

//Decryption: 
unsigned char pKey[] = {
		0x25, 0x0D, 0xCF, 0xCB, 0xFC, 0x2A, 0xCD, 0x12, 0xA7, 0xEA, 0x8B, 0x1D, 0xF9, 0xE4, 0x15, 0x59,
		0xF4, 0x1A, 0x31, 0x05, 0x35, 0xD2, 0xE4, 0x9E, 0x8C, 0xA1, 0x38, 0x9B, 0xEA, 0xC9, 0x3D, 0x5B };

unsigned char pIv[] = {
		0x7D, 0xAC, 0xEC, 0xB8, 0xDA, 0x4F, 0x11, 0x56, 0x1C, 0x7C, 0xF2, 0xC2, 0xEE, 0x02, 0xA9, 0xFA };

unsigned char CipherText[] = {
		0x91, 0xD3, 0xC4, 0x0B, 0x1D, 0xAD, 0x42, 0x79, 0x5D, 0x64, 0xC2, 0x3B, 0x5D, 0xC2, 0xBC, 0x01,
		0xEE, 0x68, 0x12, 0x6A, 0x20, 0xC3, 0x30, 0x62, 0xFB, 0x00, 0xD8, 0x51, 0x18, 0x56, 0x49, 0xB5,
		0x9D, 0x4D, 0x2F, 0x01, 0x61, 0xAB, 0x21, 0xCA, 0x00, 0x02, 0x1A, 0x22, 0x73, 0xC4, 0x9E, 0x53,
		0x04, 0x47, 0xC1, 0xBF, 0x94, 0xA3, 0xC6, 0x81, 0x0B, 0x29, 0x0F, 0x29, 0xA7, 0x0F, 0x8F, 0x4D,
		0x82, 0x88, 0x48, 0x13, 0xA3, 0x4A, 0x1D, 0x18, 0x8A, 0x69, 0x72, 0x80, 0x39, 0x16, 0x67, 0x63,
		0x78, 0x05, 0x42, 0xCE, 0x35, 0x27, 0x61, 0xA0, 0x55, 0x74, 0xF1, 0x91, 0x8B, 0xE8, 0x61, 0x29 };

int main() {
	//Struct needed
	struct AES_ctx ctx;
	AES_init_ctx_iv(&ctx, pKey, pIv);

	//Decrypting
	AES_CBC_decrypt_buffer(&ctx, CipherText, sizeof(CipherText));
	PrintHexData("PlainText", CipherText, sizeof(CipherText));

	//print the string
	printf("Data: %s \n", CipherText);
	return 0;

} 
```

Output:

<figure><img src="https://3173583452-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F992MXD5taJKwdsEBglpC%2Fuploads%2Fgit-blob-4d2dfc0ad8b6f84ef96d8f7ab1c6f97dce7884b4%2Fimage%20(77).png?alt=media" alt=""><figcaption></figcaption></figure>

#### Tiny-AES IAT

The image below shows a binary's IAT which uses Tiny-AES to perform encryption instead of WinAPIs. No cryptographic functions are visible in the IAT of the binary.

<figure><img src="https://3173583452-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F992MXD5taJKwdsEBglpC%2Fuploads%2Fgit-blob-95f508d65295fb29d88366983641facaabbe87d4%2Fimage%20(78).png?alt=media" alt=""><figcaption></figcaption></figure>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://www.udayxd.tech/notes/maldev/payload-encryption-xor-and-aes.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
